* [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp
2013-09-11 20:52 [Qemu-devel] [PATCH 0/6] QMP: re-organize documentation Luiz Capitulino
@ 2013-09-11 20:52 ` Luiz Capitulino
2013-09-11 22:08 ` Eric Blake
2013-09-11 20:52 ` [Qemu-devel] [PATCH 2/6] QMP: fix qmp-commands.txt generation path Luiz Capitulino
` (4 subsequent siblings)
5 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-11 20:52 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru
Populate it with all scripts stored in QMP/.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
QMP/qemu-ga-client | 299 ---------------------------------------------
QMP/qmp | 126 -------------------
QMP/qmp-shell | 286 -------------------------------------------
QMP/qmp.py | 190 ----------------------------
QMP/qom-fuse | 138 ---------------------
QMP/qom-get | 67 ----------
QMP/qom-list | 64 ----------
QMP/qom-set | 64 ----------
scripts/qmp/qemu-ga-client | 299 +++++++++++++++++++++++++++++++++++++++++++++
scripts/qmp/qmp | 126 +++++++++++++++++++
scripts/qmp/qmp-shell | 286 +++++++++++++++++++++++++++++++++++++++++++
scripts/qmp/qmp.py | 190 ++++++++++++++++++++++++++++
scripts/qmp/qom-fuse | 138 +++++++++++++++++++++
scripts/qmp/qom-get | 67 ++++++++++
scripts/qmp/qom-list | 64 ++++++++++
scripts/qmp/qom-set | 64 ++++++++++
16 files changed, 1234 insertions(+), 1234 deletions(-)
delete mode 100755 QMP/qemu-ga-client
delete mode 100755 QMP/qmp
delete mode 100755 QMP/qmp-shell
delete mode 100644 QMP/qmp.py
delete mode 100755 QMP/qom-fuse
delete mode 100755 QMP/qom-get
delete mode 100755 QMP/qom-list
delete mode 100755 QMP/qom-set
create mode 100755 scripts/qmp/qemu-ga-client
create mode 100755 scripts/qmp/qmp
create mode 100755 scripts/qmp/qmp-shell
create mode 100644 scripts/qmp/qmp.py
create mode 100755 scripts/qmp/qom-fuse
create mode 100755 scripts/qmp/qom-get
create mode 100755 scripts/qmp/qom-list
create mode 100755 scripts/qmp/qom-set
diff --git a/QMP/qemu-ga-client b/QMP/qemu-ga-client
deleted file mode 100755
index 46676c3..0000000
--- a/QMP/qemu-ga-client
+++ /dev/null
@@ -1,299 +0,0 @@
-#!/usr/bin/python
-
-# QEMU Guest Agent Client
-#
-# Copyright (C) 2012 Ryota Ozaki <ozaki.ryota@gmail.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
-#
-# Usage:
-#
-# Start QEMU with:
-#
-# # qemu [...] -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
-# -device virtio-serial -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
-#
-# Run the script:
-#
-# $ qemu-ga-client --address=/tmp/qga.sock <command> [args...]
-#
-# or
-#
-# $ export QGA_CLIENT_ADDRESS=/tmp/qga.sock
-# $ qemu-ga-client <command> [args...]
-#
-# For example:
-#
-# $ qemu-ga-client cat /etc/resolv.conf
-# # Generated by NetworkManager
-# nameserver 10.0.2.3
-# $ qemu-ga-client fsfreeze status
-# thawed
-# $ qemu-ga-client fsfreeze freeze
-# 2 filesystems frozen
-#
-# See also: http://wiki.qemu.org/Features/QAPI/GuestAgent
-#
-
-import base64
-import random
-
-import qmp
-
-
-class QemuGuestAgent(qmp.QEMUMonitorProtocol):
- def __getattr__(self, name):
- def wrapper(**kwds):
- return self.command('guest-' + name.replace('_', '-'), **kwds)
- return wrapper
-
-
-class QemuGuestAgentClient:
- error = QemuGuestAgent.error
-
- def __init__(self, address):
- self.qga = QemuGuestAgent(address)
- self.qga.connect(negotiate=False)
-
- def sync(self, timeout=3):
- # Avoid being blocked forever
- if not self.ping(timeout):
- raise EnvironmentError('Agent seems not alive')
- uid = random.randint(0, (1 << 32) - 1)
- while True:
- ret = self.qga.sync(id=uid)
- if isinstance(ret, int) and int(ret) == uid:
- break
-
- def __file_read_all(self, handle):
- eof = False
- data = ''
- while not eof:
- ret = self.qga.file_read(handle=handle, count=1024)
- _data = base64.b64decode(ret['buf-b64'])
- data += _data
- eof = ret['eof']
- return data
-
- def read(self, path):
- handle = self.qga.file_open(path=path)
- try:
- data = self.__file_read_all(handle)
- finally:
- self.qga.file_close(handle=handle)
- return data
-
- def info(self):
- info = self.qga.info()
-
- msgs = []
- msgs.append('version: ' + info['version'])
- msgs.append('supported_commands:')
- enabled = [c['name'] for c in info['supported_commands'] if c['enabled']]
- msgs.append('\tenabled: ' + ', '.join(enabled))
- disabled = [c['name'] for c in info['supported_commands'] if not c['enabled']]
- msgs.append('\tdisabled: ' + ', '.join(disabled))
-
- return '\n'.join(msgs)
-
- def __gen_ipv4_netmask(self, prefixlen):
- mask = int('1' * prefixlen + '0' * (32 - prefixlen), 2)
- return '.'.join([str(mask >> 24),
- str((mask >> 16) & 0xff),
- str((mask >> 8) & 0xff),
- str(mask & 0xff)])
-
- def ifconfig(self):
- nifs = self.qga.network_get_interfaces()
-
- msgs = []
- for nif in nifs:
- msgs.append(nif['name'] + ':')
- if 'ip-addresses' in nif:
- for ipaddr in nif['ip-addresses']:
- if ipaddr['ip-address-type'] == 'ipv4':
- addr = ipaddr['ip-address']
- mask = self.__gen_ipv4_netmask(int(ipaddr['prefix']))
- msgs.append("\tinet %s netmask %s" % (addr, mask))
- elif ipaddr['ip-address-type'] == 'ipv6':
- addr = ipaddr['ip-address']
- prefix = ipaddr['prefix']
- msgs.append("\tinet6 %s prefixlen %s" % (addr, prefix))
- if nif['hardware-address'] != '00:00:00:00:00:00':
- msgs.append("\tether " + nif['hardware-address'])
-
- return '\n'.join(msgs)
-
- def ping(self, timeout):
- self.qga.settimeout(timeout)
- try:
- self.qga.ping()
- except self.qga.timeout:
- return False
- return True
-
- def fsfreeze(self, cmd):
- if cmd not in ['status', 'freeze', 'thaw']:
- raise StandardError('Invalid command: ' + cmd)
-
- return getattr(self.qga, 'fsfreeze' + '_' + cmd)()
-
- def fstrim(self, minimum=0):
- return getattr(self.qga, 'fstrim')(minimum=minimum)
-
- def suspend(self, mode):
- if mode not in ['disk', 'ram', 'hybrid']:
- raise StandardError('Invalid mode: ' + mode)
-
- try:
- getattr(self.qga, 'suspend' + '_' + mode)()
- # On error exception will raise
- except self.qga.timeout:
- # On success command will timed out
- return
-
- def shutdown(self, mode='powerdown'):
- if mode not in ['powerdown', 'halt', 'reboot']:
- raise StandardError('Invalid mode: ' + mode)
-
- try:
- self.qga.shutdown(mode=mode)
- except self.qga.timeout:
- return
-
-
-def _cmd_cat(client, args):
- if len(args) != 1:
- print('Invalid argument')
- print('Usage: cat <file>')
- sys.exit(1)
- print(client.read(args[0]))
-
-
-def _cmd_fsfreeze(client, args):
- usage = 'Usage: fsfreeze status|freeze|thaw'
- if len(args) != 1:
- print('Invalid argument')
- print(usage)
- sys.exit(1)
- if args[0] not in ['status', 'freeze', 'thaw']:
- print('Invalid command: ' + args[0])
- print(usage)
- sys.exit(1)
- cmd = args[0]
- ret = client.fsfreeze(cmd)
- if cmd == 'status':
- print(ret)
- elif cmd == 'freeze':
- print("%d filesystems frozen" % ret)
- else:
- print("%d filesystems thawed" % ret)
-
-
-def _cmd_fstrim(client, args):
- if len(args) == 0:
- minimum = 0
- else:
- minimum = int(args[0])
- print(client.fstrim(minimum))
-
-
-def _cmd_ifconfig(client, args):
- print(client.ifconfig())
-
-
-def _cmd_info(client, args):
- print(client.info())
-
-
-def _cmd_ping(client, args):
- if len(args) == 0:
- timeout = 3
- else:
- timeout = float(args[0])
- alive = client.ping(timeout)
- if not alive:
- print("Not responded in %s sec" % args[0])
- sys.exit(1)
-
-
-def _cmd_suspend(client, args):
- usage = 'Usage: suspend disk|ram|hybrid'
- if len(args) != 1:
- print('Less argument')
- print(usage)
- sys.exit(1)
- if args[0] not in ['disk', 'ram', 'hybrid']:
- print('Invalid command: ' + args[0])
- print(usage)
- sys.exit(1)
- client.suspend(args[0])
-
-
-def _cmd_shutdown(client, args):
- client.shutdown()
-_cmd_powerdown = _cmd_shutdown
-
-
-def _cmd_halt(client, args):
- client.shutdown('halt')
-
-
-def _cmd_reboot(client, args):
- client.shutdown('reboot')
-
-
-commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m]
-
-
-def main(address, cmd, args):
- if not os.path.exists(address):
- print('%s not found' % address)
- sys.exit(1)
-
- if cmd not in commands:
- print('Invalid command: ' + cmd)
- print('Available commands: ' + ', '.join(commands))
- sys.exit(1)
-
- try:
- client = QemuGuestAgentClient(address)
- except QemuGuestAgent.error, e:
- import errno
-
- print(e)
- if e.errno == errno.ECONNREFUSED:
- print('Hint: qemu is not running?')
- sys.exit(1)
-
- if cmd != 'ping':
- client.sync()
-
- globals()['_cmd_' + cmd](client, args)
-
-
-if __name__ == '__main__':
- import sys
- import os
- import optparse
-
- address = os.environ['QGA_CLIENT_ADDRESS'] if 'QGA_CLIENT_ADDRESS' in os.environ else None
-
- usage = "%prog [--address=<unix_path>|<ipv4_address>] <command> [args...]\n"
- usage += '<command>: ' + ', '.join(commands)
- parser = optparse.OptionParser(usage=usage)
- parser.add_option('--address', action='store', type='string',
- default=address, help='Specify a ip:port pair or a unix socket path')
- options, args = parser.parse_args()
-
- address = options.address
- if address is None:
- parser.error('address is not specified')
- sys.exit(1)
-
- if len(args) == 0:
- parser.error('Less argument')
- sys.exit(1)
-
- main(address, args[0], args[1:])
diff --git a/QMP/qmp b/QMP/qmp
deleted file mode 100755
index 1db3c7f..0000000
--- a/QMP/qmp
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/python
-#
-# QMP command line tool
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPLv2 or later.
-# See the COPYING file in the top-level directory.
-
-import sys, os
-from qmp import QEMUMonitorProtocol
-
-def print_response(rsp, prefix=[]):
- if type(rsp) == list:
- i = 0
- for item in rsp:
- if prefix == []:
- prefix = ['item']
- print_response(item, prefix[:-1] + ['%s[%d]' % (prefix[-1], i)])
- i += 1
- elif type(rsp) == dict:
- for key in rsp.keys():
- print_response(rsp[key], prefix + [key])
- else:
- if len(prefix):
- print '%s: %s' % ('.'.join(prefix), rsp)
- else:
- print '%s' % (rsp)
-
-def main(args):
- path = None
-
- # Use QMP_PATH if it's set
- if os.environ.has_key('QMP_PATH'):
- path = os.environ['QMP_PATH']
-
- while len(args):
- arg = args[0]
-
- if arg.startswith('--'):
- arg = arg[2:]
- if arg.find('=') == -1:
- value = True
- else:
- arg, value = arg.split('=', 1)
-
- if arg in ['path']:
- if type(value) == str:
- path = value
- elif arg in ['help']:
- os.execlp('man', 'man', 'qmp')
- else:
- print 'Unknown argument "%s"' % arg
-
- args = args[1:]
- else:
- break
-
- if not path:
- print "QMP path isn't set, use --path=qmp-monitor-address or set QMP_PATH"
- return 1
-
- if len(args):
- command, args = args[0], args[1:]
- else:
- print 'No command found'
- print 'Usage: "qmp [--path=qmp-monitor-address] qmp-cmd arguments"'
- return 1
-
- if command in ['help']:
- os.execlp('man', 'man', 'qmp')
-
- srv = QEMUMonitorProtocol(path)
- srv.connect()
-
- def do_command(srv, cmd, **kwds):
- rsp = srv.cmd(cmd, kwds)
- if rsp.has_key('error'):
- raise Exception(rsp['error']['desc'])
- return rsp['return']
-
- commands = map(lambda x: x['name'], do_command(srv, 'query-commands'))
-
- srv.close()
-
- if command not in commands:
- fullcmd = 'qmp-%s' % command
- try:
- os.environ['QMP_PATH'] = path
- os.execvp(fullcmd, [fullcmd] + args)
- except OSError, (errno, msg):
- if errno == 2:
- print 'Command "%s" not found.' % (fullcmd)
- return 1
- raise
- return 0
-
- srv = QEMUMonitorProtocol(path)
- srv.connect()
-
- arguments = {}
- for arg in args:
- if not arg.startswith('--'):
- print 'Unknown argument "%s"' % arg
- return 1
-
- arg = arg[2:]
- if arg.find('=') == -1:
- value = True
- else:
- arg, value = arg.split('=', 1)
-
- if arg in ['help']:
- os.execlp('man', 'man', 'qmp-%s' % command)
- return 1
-
- arguments[arg] = value
-
- rsp = do_command(srv, command, **arguments)
- print_response(rsp)
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/QMP/qmp-shell b/QMP/qmp-shell
deleted file mode 100755
index 73cb3b6..0000000
--- a/QMP/qmp-shell
+++ /dev/null
@@ -1,286 +0,0 @@
-#!/usr/bin/python
-#
-# Low-level QEMU shell on top of QMP.
-#
-# Copyright (C) 2009, 2010 Red Hat Inc.
-#
-# Authors:
-# Luiz Capitulino <lcapitulino@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
-#
-# Usage:
-#
-# Start QEMU with:
-#
-# # qemu [...] -qmp unix:./qmp-sock,server
-#
-# Run the shell:
-#
-# $ qmp-shell ./qmp-sock
-#
-# Commands have the following format:
-#
-# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
-#
-# For example:
-#
-# (QEMU) device_add driver=e1000 id=net1
-# {u'return': {}}
-# (QEMU)
-
-import qmp
-import readline
-import sys
-import pprint
-
-class QMPCompleter(list):
- def complete(self, text, state):
- for cmd in self:
- if cmd.startswith(text):
- if not state:
- return cmd
- else:
- state -= 1
-
-class QMPShellError(Exception):
- pass
-
-class QMPShellBadPort(QMPShellError):
- pass
-
-# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
-# _execute_cmd()). Let's design a better one.
-class QMPShell(qmp.QEMUMonitorProtocol):
- def __init__(self, address, pp=None):
- qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
- self._greeting = None
- self._completer = None
- self._pp = pp
-
- def __get_address(self, arg):
- """
- Figure out if the argument is in the port:host form, if it's not it's
- probably a file path.
- """
- addr = arg.split(':')
- if len(addr) == 2:
- try:
- port = int(addr[1])
- except ValueError:
- raise QMPShellBadPort
- return ( addr[0], port )
- # socket path
- return arg
-
- def _fill_completion(self):
- for cmd in self.cmd('query-commands')['return']:
- self._completer.append(cmd['name'])
-
- def __completer_setup(self):
- self._completer = QMPCompleter()
- self._fill_completion()
- readline.set_completer(self._completer.complete)
- readline.parse_and_bind("tab: complete")
- # XXX: default delimiters conflict with some command names (eg. query-),
- # clearing everything as it doesn't seem to matter
- readline.set_completer_delims('')
-
- def __build_cmd(self, cmdline):
- """
- Build a QMP input object from a user provided command-line in the
- following format:
-
- < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
- """
- cmdargs = cmdline.split()
- qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
- for arg in cmdargs[1:]:
- opt = arg.split('=')
- try:
- if(len(opt) > 2):
- opt[1] = '='.join(opt[1:])
- value = int(opt[1])
- except ValueError:
- if opt[1] == 'true':
- value = True
- elif opt[1] == 'false':
- value = False
- else:
- value = opt[1]
- qmpcmd['arguments'][opt[0]] = value
- return qmpcmd
-
- def _execute_cmd(self, cmdline):
- try:
- qmpcmd = self.__build_cmd(cmdline)
- except:
- print 'command format: <command-name> ',
- print '[arg-name1=arg1] ... [arg-nameN=argN]'
- return True
- resp = self.cmd_obj(qmpcmd)
- if resp is None:
- print 'Disconnected'
- return False
-
- if self._pp is not None:
- self._pp.pprint(resp)
- else:
- print resp
- return True
-
- def connect(self):
- self._greeting = qmp.QEMUMonitorProtocol.connect(self)
- self.__completer_setup()
-
- def show_banner(self, msg='Welcome to the QMP low-level shell!'):
- print msg
- version = self._greeting['QMP']['version']['qemu']
- print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
-
- def read_exec_command(self, prompt):
- """
- Read and execute a command.
-
- @return True if execution was ok, return False if disconnected.
- """
- try:
- cmdline = raw_input(prompt)
- except EOFError:
- print
- return False
- if cmdline == '':
- for ev in self.get_events():
- print ev
- self.clear_events()
- return True
- else:
- return self._execute_cmd(cmdline)
-
-class HMPShell(QMPShell):
- def __init__(self, address):
- QMPShell.__init__(self, address)
- self.__cpu_index = 0
-
- def __cmd_completion(self):
- for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
- if cmd and cmd[0] != '[' and cmd[0] != '\t':
- name = cmd.split()[0] # drop help text
- if name == 'info':
- continue
- if name.find('|') != -1:
- # Command in the form 'foobar|f' or 'f|foobar', take the
- # full name
- opt = name.split('|')
- if len(opt[0]) == 1:
- name = opt[1]
- else:
- name = opt[0]
- self._completer.append(name)
- self._completer.append('help ' + name) # help completion
-
- def __info_completion(self):
- for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
- if cmd:
- self._completer.append('info ' + cmd.split()[1])
-
- def __other_completion(self):
- # special cases
- self._completer.append('help info')
-
- def _fill_completion(self):
- self.__cmd_completion()
- self.__info_completion()
- self.__other_completion()
-
- def __cmd_passthrough(self, cmdline, cpu_index = 0):
- return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
- { 'command-line': cmdline,
- 'cpu-index': cpu_index } })
-
- def _execute_cmd(self, cmdline):
- if cmdline.split()[0] == "cpu":
- # trap the cpu command, it requires special setting
- try:
- idx = int(cmdline.split()[1])
- if not 'return' in self.__cmd_passthrough('info version', idx):
- print 'bad CPU index'
- return True
- self.__cpu_index = idx
- except ValueError:
- print 'cpu command takes an integer argument'
- return True
- resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
- if resp is None:
- print 'Disconnected'
- return False
- assert 'return' in resp or 'error' in resp
- if 'return' in resp:
- # Success
- if len(resp['return']) > 0:
- print resp['return'],
- else:
- # Error
- print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
- return True
-
- def show_banner(self):
- QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
-
-def die(msg):
- sys.stderr.write('ERROR: %s\n' % msg)
- sys.exit(1)
-
-def fail_cmdline(option=None):
- if option:
- sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
- sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
- sys.exit(1)
-
-def main():
- addr = ''
- qemu = None
- hmp = False
- pp = None
-
- try:
- for arg in sys.argv[1:]:
- if arg == "-H":
- if qemu is not None:
- fail_cmdline(arg)
- hmp = True
- elif arg == "-p":
- if pp is not None:
- fail_cmdline(arg)
- pp = pprint.PrettyPrinter(indent=4)
- else:
- if qemu is not None:
- fail_cmdline(arg)
- if hmp:
- qemu = HMPShell(arg)
- else:
- qemu = QMPShell(arg, pp)
- addr = arg
-
- if qemu is None:
- fail_cmdline()
- except QMPShellBadPort:
- die('bad port number in command-line')
-
- try:
- qemu.connect()
- except qmp.QMPConnectError:
- die('Didn\'t get QMP greeting message')
- except qmp.QMPCapabilitiesError:
- die('Could not negotiate capabilities')
- except qemu.error:
- die('Could not connect to %s' % addr)
-
- qemu.show_banner()
- while qemu.read_exec_command('(QEMU) '):
- pass
- qemu.close()
-
-if __name__ == '__main__':
- main()
diff --git a/QMP/qmp.py b/QMP/qmp.py
deleted file mode 100644
index c551df1..0000000
--- a/QMP/qmp.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# QEMU Monitor Protocol Python class
-#
-# Copyright (C) 2009, 2010 Red Hat Inc.
-#
-# Authors:
-# Luiz Capitulino <lcapitulino@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
-
-import json
-import errno
-import socket
-
-class QMPError(Exception):
- pass
-
-class QMPConnectError(QMPError):
- pass
-
-class QMPCapabilitiesError(QMPError):
- pass
-
-class QEMUMonitorProtocol:
- def __init__(self, address, server=False):
- """
- Create a QEMUMonitorProtocol class.
-
- @param address: QEMU address, can be either a unix socket path (string)
- or a tuple in the form ( address, port ) for a TCP
- connection
- @param server: server mode listens on the socket (bool)
- @raise socket.error on socket connection errors
- @note No connection is established, this is done by the connect() or
- accept() methods
- """
- self.__events = []
- self.__address = address
- self.__sock = self.__get_sock()
- if server:
- self.__sock.bind(self.__address)
- self.__sock.listen(1)
-
- def __get_sock(self):
- if isinstance(self.__address, tuple):
- family = socket.AF_INET
- else:
- family = socket.AF_UNIX
- return socket.socket(family, socket.SOCK_STREAM)
-
- def __negotiate_capabilities(self):
- greeting = self.__json_read()
- if greeting is None or not greeting.has_key('QMP'):
- raise QMPConnectError
- # Greeting seems ok, negotiate capabilities
- resp = self.cmd('qmp_capabilities')
- if "return" in resp:
- return greeting
- raise QMPCapabilitiesError
-
- def __json_read(self, only_event=False):
- while True:
- data = self.__sockfile.readline()
- if not data:
- return
- resp = json.loads(data)
- if 'event' in resp:
- self.__events.append(resp)
- if not only_event:
- continue
- return resp
-
- error = socket.error
-
- def connect(self, negotiate=True):
- """
- Connect to the QMP Monitor and perform capabilities negotiation.
-
- @return QMP greeting dict
- @raise socket.error on socket connection errors
- @raise QMPConnectError if the greeting is not received
- @raise QMPCapabilitiesError if fails to negotiate capabilities
- """
- self.__sock.connect(self.__address)
- self.__sockfile = self.__sock.makefile()
- if negotiate:
- return self.__negotiate_capabilities()
-
- def accept(self):
- """
- Await connection from QMP Monitor and perform capabilities negotiation.
-
- @return QMP greeting dict
- @raise socket.error on socket connection errors
- @raise QMPConnectError if the greeting is not received
- @raise QMPCapabilitiesError if fails to negotiate capabilities
- """
- self.__sock, _ = self.__sock.accept()
- self.__sockfile = self.__sock.makefile()
- return self.__negotiate_capabilities()
-
- def cmd_obj(self, qmp_cmd):
- """
- Send a QMP command to the QMP Monitor.
-
- @param qmp_cmd: QMP command to be sent as a Python dict
- @return QMP response as a Python dict or None if the connection has
- been closed
- """
- try:
- self.__sock.sendall(json.dumps(qmp_cmd))
- except socket.error, err:
- if err[0] == errno.EPIPE:
- return
- raise socket.error(err)
- return self.__json_read()
-
- def cmd(self, name, args=None, id=None):
- """
- Build a QMP command and send it to the QMP Monitor.
-
- @param name: command name (string)
- @param args: command arguments (dict)
- @param id: command id (dict, list, string or int)
- """
- qmp_cmd = { 'execute': name }
- if args:
- qmp_cmd['arguments'] = args
- if id:
- qmp_cmd['id'] = id
- return self.cmd_obj(qmp_cmd)
-
- def command(self, cmd, **kwds):
- ret = self.cmd(cmd, kwds)
- if ret.has_key('error'):
- raise Exception(ret['error']['desc'])
- return ret['return']
-
- def pull_event(self, wait=False):
- """
- Get and delete the first available QMP event.
-
- @param wait: block until an event is available (bool)
- """
- self.__sock.setblocking(0)
- try:
- self.__json_read()
- except socket.error, err:
- if err[0] == errno.EAGAIN:
- # No data available
- pass
- self.__sock.setblocking(1)
- if not self.__events and wait:
- self.__json_read(only_event=True)
- event = self.__events[0]
- del self.__events[0]
- return event
-
- def get_events(self, wait=False):
- """
- Get a list of available QMP events.
-
- @param wait: block until an event is available (bool)
- """
- self.__sock.setblocking(0)
- try:
- self.__json_read()
- except socket.error, err:
- if err[0] == errno.EAGAIN:
- # No data available
- pass
- self.__sock.setblocking(1)
- if not self.__events and wait:
- self.__json_read(only_event=True)
- return self.__events
-
- def clear_events(self):
- """
- Clear current list of pending events.
- """
- self.__events = []
-
- def close(self):
- self.__sock.close()
- self.__sockfile.close()
-
- timeout = socket.timeout
-
- def settimeout(self, timeout):
- self.__sock.settimeout(timeout)
diff --git a/QMP/qom-fuse b/QMP/qom-fuse
deleted file mode 100755
index 5c6754a..0000000
--- a/QMP/qom-fuse
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/python
-##
-# QEMU Object Model test tools
-#
-# Copyright IBM, Corp. 2012
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or later. See
-# the COPYING file in the top-level directory.
-##
-
-import fuse, stat
-from fuse import Fuse
-import os, posix
-from errno import *
-from qmp import QEMUMonitorProtocol
-
-fuse.fuse_python_api = (0, 2)
-
-class QOMFS(Fuse):
- def __init__(self, qmp, *args, **kwds):
- Fuse.__init__(self, *args, **kwds)
- self.qmp = qmp
- self.qmp.connect()
- self.ino_map = {}
- self.ino_count = 1
-
- def get_ino(self, path):
- if self.ino_map.has_key(path):
- return self.ino_map[path]
- self.ino_map[path] = self.ino_count
- self.ino_count += 1
- return self.ino_map[path]
-
- def is_object(self, path):
- try:
- items = self.qmp.command('qom-list', path=path)
- return True
- except:
- return False
-
- def is_property(self, path):
- try:
- path, prop = path.rsplit('/', 1)
- for item in self.qmp.command('qom-list', path=path):
- if item['name'] == prop:
- return True
- return False
- except:
- return False
-
- def is_link(self, path):
- try:
- path, prop = path.rsplit('/', 1)
- for item in self.qmp.command('qom-list', path=path):
- if item['name'] == prop:
- if item['type'].startswith('link<'):
- return True
- return False
- return False
- except:
- return False
-
- def read(self, path, length, offset):
- if not self.is_property(path):
- return -ENOENT
-
- path, prop = path.rsplit('/', 1)
- try:
- data = str(self.qmp.command('qom-get', path=path, property=prop))
- data += '\n' # make values shell friendly
- except:
- return -EPERM
-
- if offset > len(data):
- return ''
-
- return str(data[offset:][:length])
-
- def readlink(self, path):
- if not self.is_link(path):
- return False
- path, prop = path.rsplit('/', 1)
- prefix = '/'.join(['..'] * (len(path.split('/')) - 1))
- return prefix + str(self.qmp.command('qom-get', path=path,
- property=prop))
-
- def getattr(self, path):
- if self.is_link(path):
- value = posix.stat_result((0755 | stat.S_IFLNK,
- self.get_ino(path),
- 0,
- 2,
- 1000,
- 1000,
- 4096,
- 0,
- 0,
- 0))
- elif self.is_object(path):
- value = posix.stat_result((0755 | stat.S_IFDIR,
- self.get_ino(path),
- 0,
- 2,
- 1000,
- 1000,
- 4096,
- 0,
- 0,
- 0))
- elif self.is_property(path):
- value = posix.stat_result((0644 | stat.S_IFREG,
- self.get_ino(path),
- 0,
- 1,
- 1000,
- 1000,
- 4096,
- 0,
- 0,
- 0))
- else:
- value = -ENOENT
- return value
-
- def readdir(self, path, offset):
- yield fuse.Direntry('.')
- yield fuse.Direntry('..')
- for item in self.qmp.command('qom-list', path=path):
- yield fuse.Direntry(str(item['name']))
-
-if __name__ == '__main__':
- import sys, os
-
- fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
- fs.main(sys.argv)
diff --git a/QMP/qom-get b/QMP/qom-get
deleted file mode 100755
index 0172c69..0000000
--- a/QMP/qom-get
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/python
-##
-# QEMU Object Model test tools
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or later. See
-# the COPYING file in the top-level directory.
-##
-
-import sys
-import os
-from qmp import QEMUMonitorProtocol
-
-cmd, args = sys.argv[0], sys.argv[1:]
-socket_path = None
-path = None
-prop = None
-
-def usage():
- return '''environment variables:
- QMP_SOCKET=<path | addr:port>
-usage:
- %s [-h] [-s <QMP socket path | addr:port>] <path>.<property>
-''' % cmd
-
-def usage_error(error_msg = "unspecified error"):
- sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
- exit(1)
-
-if len(args) > 0:
- if args[0] == "-h":
- print usage()
- exit(0);
- elif args[0] == "-s":
- try:
- socket_path = args[1]
- except:
- usage_error("missing argument: QMP socket path or address");
- args = args[2:]
-
-if not socket_path:
- if os.environ.has_key('QMP_SOCKET'):
- socket_path = os.environ['QMP_SOCKET']
- else:
- usage_error("no QMP socket path or address given");
-
-if len(args) > 0:
- try:
- path, prop = args[0].rsplit('.', 1)
- except:
- usage_error("invalid format for path/property/value")
-else:
- usage_error("not enough arguments")
-
-srv = QEMUMonitorProtocol(socket_path)
-srv.connect()
-
-rsp = srv.command('qom-get', path=path, property=prop)
-if type(rsp) == dict:
- for i in rsp.keys():
- print '%s: %s' % (i, rsp[i])
-else:
- print rsp
diff --git a/QMP/qom-list b/QMP/qom-list
deleted file mode 100755
index 1e7cc6c..0000000
--- a/QMP/qom-list
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/python
-##
-# QEMU Object Model test tools
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or later. See
-# the COPYING file in the top-level directory.
-##
-
-import sys
-import os
-from qmp import QEMUMonitorProtocol
-
-cmd, args = sys.argv[0], sys.argv[1:]
-socket_path = None
-path = None
-prop = None
-
-def usage():
- return '''environment variables:
- QMP_SOCKET=<path | addr:port>
-usage:
- %s [-h] [-s <QMP socket path | addr:port>] [<path>]
-''' % cmd
-
-def usage_error(error_msg = "unspecified error"):
- sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
- exit(1)
-
-if len(args) > 0:
- if args[0] == "-h":
- print usage()
- exit(0);
- elif args[0] == "-s":
- try:
- socket_path = args[1]
- except:
- usage_error("missing argument: QMP socket path or address");
- args = args[2:]
-
-if not socket_path:
- if os.environ.has_key('QMP_SOCKET'):
- socket_path = os.environ['QMP_SOCKET']
- else:
- usage_error("no QMP socket path or address given");
-
-srv = QEMUMonitorProtocol(socket_path)
-srv.connect()
-
-if len(args) == 0:
- print '/'
- sys.exit(0)
-
-for item in srv.command('qom-list', path=args[0]):
- if item['type'].startswith('child<'):
- print '%s/' % item['name']
- elif item['type'].startswith('link<'):
- print '@%s/' % item['name']
- else:
- print '%s' % item['name']
diff --git a/QMP/qom-set b/QMP/qom-set
deleted file mode 100755
index 54ecfec..0000000
--- a/QMP/qom-set
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/python
-##
-# QEMU Object Model test tools
-#
-# Copyright IBM, Corp. 2011
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or later. See
-# the COPYING file in the top-level directory.
-##
-
-import sys
-import os
-from qmp import QEMUMonitorProtocol
-
-cmd, args = sys.argv[0], sys.argv[1:]
-socket_path = None
-path = None
-prop = None
-value = None
-
-def usage():
- return '''environment variables:
- QMP_SOCKET=<path | addr:port>
-usage:
- %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> <value>
-''' % cmd
-
-def usage_error(error_msg = "unspecified error"):
- sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
- exit(1)
-
-if len(args) > 0:
- if args[0] == "-h":
- print usage()
- exit(0);
- elif args[0] == "-s":
- try:
- socket_path = args[1]
- except:
- usage_error("missing argument: QMP socket path or address");
- args = args[2:]
-
-if not socket_path:
- if os.environ.has_key('QMP_SOCKET'):
- socket_path = os.environ['QMP_SOCKET']
- else:
- usage_error("no QMP socket path or address given");
-
-if len(args) > 1:
- try:
- path, prop = args[0].rsplit('.', 1)
- except:
- usage_error("invalid format for path/property/value")
- value = args[1]
-else:
- usage_error("not enough arguments")
-
-srv = QEMUMonitorProtocol(socket_path)
-srv.connect()
-
-print srv.command('qom-set', path=path, property=prop, value=sys.argv[2])
diff --git a/scripts/qmp/qemu-ga-client b/scripts/qmp/qemu-ga-client
new file mode 100755
index 0000000..46676c3
--- /dev/null
+++ b/scripts/qmp/qemu-ga-client
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+
+# QEMU Guest Agent Client
+#
+# Copyright (C) 2012 Ryota Ozaki <ozaki.ryota@gmail.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+# Usage:
+#
+# Start QEMU with:
+#
+# # qemu [...] -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
+# -device virtio-serial -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
+#
+# Run the script:
+#
+# $ qemu-ga-client --address=/tmp/qga.sock <command> [args...]
+#
+# or
+#
+# $ export QGA_CLIENT_ADDRESS=/tmp/qga.sock
+# $ qemu-ga-client <command> [args...]
+#
+# For example:
+#
+# $ qemu-ga-client cat /etc/resolv.conf
+# # Generated by NetworkManager
+# nameserver 10.0.2.3
+# $ qemu-ga-client fsfreeze status
+# thawed
+# $ qemu-ga-client fsfreeze freeze
+# 2 filesystems frozen
+#
+# See also: http://wiki.qemu.org/Features/QAPI/GuestAgent
+#
+
+import base64
+import random
+
+import qmp
+
+
+class QemuGuestAgent(qmp.QEMUMonitorProtocol):
+ def __getattr__(self, name):
+ def wrapper(**kwds):
+ return self.command('guest-' + name.replace('_', '-'), **kwds)
+ return wrapper
+
+
+class QemuGuestAgentClient:
+ error = QemuGuestAgent.error
+
+ def __init__(self, address):
+ self.qga = QemuGuestAgent(address)
+ self.qga.connect(negotiate=False)
+
+ def sync(self, timeout=3):
+ # Avoid being blocked forever
+ if not self.ping(timeout):
+ raise EnvironmentError('Agent seems not alive')
+ uid = random.randint(0, (1 << 32) - 1)
+ while True:
+ ret = self.qga.sync(id=uid)
+ if isinstance(ret, int) and int(ret) == uid:
+ break
+
+ def __file_read_all(self, handle):
+ eof = False
+ data = ''
+ while not eof:
+ ret = self.qga.file_read(handle=handle, count=1024)
+ _data = base64.b64decode(ret['buf-b64'])
+ data += _data
+ eof = ret['eof']
+ return data
+
+ def read(self, path):
+ handle = self.qga.file_open(path=path)
+ try:
+ data = self.__file_read_all(handle)
+ finally:
+ self.qga.file_close(handle=handle)
+ return data
+
+ def info(self):
+ info = self.qga.info()
+
+ msgs = []
+ msgs.append('version: ' + info['version'])
+ msgs.append('supported_commands:')
+ enabled = [c['name'] for c in info['supported_commands'] if c['enabled']]
+ msgs.append('\tenabled: ' + ', '.join(enabled))
+ disabled = [c['name'] for c in info['supported_commands'] if not c['enabled']]
+ msgs.append('\tdisabled: ' + ', '.join(disabled))
+
+ return '\n'.join(msgs)
+
+ def __gen_ipv4_netmask(self, prefixlen):
+ mask = int('1' * prefixlen + '0' * (32 - prefixlen), 2)
+ return '.'.join([str(mask >> 24),
+ str((mask >> 16) & 0xff),
+ str((mask >> 8) & 0xff),
+ str(mask & 0xff)])
+
+ def ifconfig(self):
+ nifs = self.qga.network_get_interfaces()
+
+ msgs = []
+ for nif in nifs:
+ msgs.append(nif['name'] + ':')
+ if 'ip-addresses' in nif:
+ for ipaddr in nif['ip-addresses']:
+ if ipaddr['ip-address-type'] == 'ipv4':
+ addr = ipaddr['ip-address']
+ mask = self.__gen_ipv4_netmask(int(ipaddr['prefix']))
+ msgs.append("\tinet %s netmask %s" % (addr, mask))
+ elif ipaddr['ip-address-type'] == 'ipv6':
+ addr = ipaddr['ip-address']
+ prefix = ipaddr['prefix']
+ msgs.append("\tinet6 %s prefixlen %s" % (addr, prefix))
+ if nif['hardware-address'] != '00:00:00:00:00:00':
+ msgs.append("\tether " + nif['hardware-address'])
+
+ return '\n'.join(msgs)
+
+ def ping(self, timeout):
+ self.qga.settimeout(timeout)
+ try:
+ self.qga.ping()
+ except self.qga.timeout:
+ return False
+ return True
+
+ def fsfreeze(self, cmd):
+ if cmd not in ['status', 'freeze', 'thaw']:
+ raise StandardError('Invalid command: ' + cmd)
+
+ return getattr(self.qga, 'fsfreeze' + '_' + cmd)()
+
+ def fstrim(self, minimum=0):
+ return getattr(self.qga, 'fstrim')(minimum=minimum)
+
+ def suspend(self, mode):
+ if mode not in ['disk', 'ram', 'hybrid']:
+ raise StandardError('Invalid mode: ' + mode)
+
+ try:
+ getattr(self.qga, 'suspend' + '_' + mode)()
+ # On error exception will raise
+ except self.qga.timeout:
+ # On success command will timed out
+ return
+
+ def shutdown(self, mode='powerdown'):
+ if mode not in ['powerdown', 'halt', 'reboot']:
+ raise StandardError('Invalid mode: ' + mode)
+
+ try:
+ self.qga.shutdown(mode=mode)
+ except self.qga.timeout:
+ return
+
+
+def _cmd_cat(client, args):
+ if len(args) != 1:
+ print('Invalid argument')
+ print('Usage: cat <file>')
+ sys.exit(1)
+ print(client.read(args[0]))
+
+
+def _cmd_fsfreeze(client, args):
+ usage = 'Usage: fsfreeze status|freeze|thaw'
+ if len(args) != 1:
+ print('Invalid argument')
+ print(usage)
+ sys.exit(1)
+ if args[0] not in ['status', 'freeze', 'thaw']:
+ print('Invalid command: ' + args[0])
+ print(usage)
+ sys.exit(1)
+ cmd = args[0]
+ ret = client.fsfreeze(cmd)
+ if cmd == 'status':
+ print(ret)
+ elif cmd == 'freeze':
+ print("%d filesystems frozen" % ret)
+ else:
+ print("%d filesystems thawed" % ret)
+
+
+def _cmd_fstrim(client, args):
+ if len(args) == 0:
+ minimum = 0
+ else:
+ minimum = int(args[0])
+ print(client.fstrim(minimum))
+
+
+def _cmd_ifconfig(client, args):
+ print(client.ifconfig())
+
+
+def _cmd_info(client, args):
+ print(client.info())
+
+
+def _cmd_ping(client, args):
+ if len(args) == 0:
+ timeout = 3
+ else:
+ timeout = float(args[0])
+ alive = client.ping(timeout)
+ if not alive:
+ print("Not responded in %s sec" % args[0])
+ sys.exit(1)
+
+
+def _cmd_suspend(client, args):
+ usage = 'Usage: suspend disk|ram|hybrid'
+ if len(args) != 1:
+ print('Less argument')
+ print(usage)
+ sys.exit(1)
+ if args[0] not in ['disk', 'ram', 'hybrid']:
+ print('Invalid command: ' + args[0])
+ print(usage)
+ sys.exit(1)
+ client.suspend(args[0])
+
+
+def _cmd_shutdown(client, args):
+ client.shutdown()
+_cmd_powerdown = _cmd_shutdown
+
+
+def _cmd_halt(client, args):
+ client.shutdown('halt')
+
+
+def _cmd_reboot(client, args):
+ client.shutdown('reboot')
+
+
+commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m]
+
+
+def main(address, cmd, args):
+ if not os.path.exists(address):
+ print('%s not found' % address)
+ sys.exit(1)
+
+ if cmd not in commands:
+ print('Invalid command: ' + cmd)
+ print('Available commands: ' + ', '.join(commands))
+ sys.exit(1)
+
+ try:
+ client = QemuGuestAgentClient(address)
+ except QemuGuestAgent.error, e:
+ import errno
+
+ print(e)
+ if e.errno == errno.ECONNREFUSED:
+ print('Hint: qemu is not running?')
+ sys.exit(1)
+
+ if cmd != 'ping':
+ client.sync()
+
+ globals()['_cmd_' + cmd](client, args)
+
+
+if __name__ == '__main__':
+ import sys
+ import os
+ import optparse
+
+ address = os.environ['QGA_CLIENT_ADDRESS'] if 'QGA_CLIENT_ADDRESS' in os.environ else None
+
+ usage = "%prog [--address=<unix_path>|<ipv4_address>] <command> [args...]\n"
+ usage += '<command>: ' + ', '.join(commands)
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('--address', action='store', type='string',
+ default=address, help='Specify a ip:port pair or a unix socket path')
+ options, args = parser.parse_args()
+
+ address = options.address
+ if address is None:
+ parser.error('address is not specified')
+ sys.exit(1)
+
+ if len(args) == 0:
+ parser.error('Less argument')
+ sys.exit(1)
+
+ main(address, args[0], args[1:])
diff --git a/scripts/qmp/qmp b/scripts/qmp/qmp
new file mode 100755
index 0000000..1db3c7f
--- /dev/null
+++ b/scripts/qmp/qmp
@@ -0,0 +1,126 @@
+#!/usr/bin/python
+#
+# QMP command line tool
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2 or later.
+# See the COPYING file in the top-level directory.
+
+import sys, os
+from qmp import QEMUMonitorProtocol
+
+def print_response(rsp, prefix=[]):
+ if type(rsp) == list:
+ i = 0
+ for item in rsp:
+ if prefix == []:
+ prefix = ['item']
+ print_response(item, prefix[:-1] + ['%s[%d]' % (prefix[-1], i)])
+ i += 1
+ elif type(rsp) == dict:
+ for key in rsp.keys():
+ print_response(rsp[key], prefix + [key])
+ else:
+ if len(prefix):
+ print '%s: %s' % ('.'.join(prefix), rsp)
+ else:
+ print '%s' % (rsp)
+
+def main(args):
+ path = None
+
+ # Use QMP_PATH if it's set
+ if os.environ.has_key('QMP_PATH'):
+ path = os.environ['QMP_PATH']
+
+ while len(args):
+ arg = args[0]
+
+ if arg.startswith('--'):
+ arg = arg[2:]
+ if arg.find('=') == -1:
+ value = True
+ else:
+ arg, value = arg.split('=', 1)
+
+ if arg in ['path']:
+ if type(value) == str:
+ path = value
+ elif arg in ['help']:
+ os.execlp('man', 'man', 'qmp')
+ else:
+ print 'Unknown argument "%s"' % arg
+
+ args = args[1:]
+ else:
+ break
+
+ if not path:
+ print "QMP path isn't set, use --path=qmp-monitor-address or set QMP_PATH"
+ return 1
+
+ if len(args):
+ command, args = args[0], args[1:]
+ else:
+ print 'No command found'
+ print 'Usage: "qmp [--path=qmp-monitor-address] qmp-cmd arguments"'
+ return 1
+
+ if command in ['help']:
+ os.execlp('man', 'man', 'qmp')
+
+ srv = QEMUMonitorProtocol(path)
+ srv.connect()
+
+ def do_command(srv, cmd, **kwds):
+ rsp = srv.cmd(cmd, kwds)
+ if rsp.has_key('error'):
+ raise Exception(rsp['error']['desc'])
+ return rsp['return']
+
+ commands = map(lambda x: x['name'], do_command(srv, 'query-commands'))
+
+ srv.close()
+
+ if command not in commands:
+ fullcmd = 'qmp-%s' % command
+ try:
+ os.environ['QMP_PATH'] = path
+ os.execvp(fullcmd, [fullcmd] + args)
+ except OSError, (errno, msg):
+ if errno == 2:
+ print 'Command "%s" not found.' % (fullcmd)
+ return 1
+ raise
+ return 0
+
+ srv = QEMUMonitorProtocol(path)
+ srv.connect()
+
+ arguments = {}
+ for arg in args:
+ if not arg.startswith('--'):
+ print 'Unknown argument "%s"' % arg
+ return 1
+
+ arg = arg[2:]
+ if arg.find('=') == -1:
+ value = True
+ else:
+ arg, value = arg.split('=', 1)
+
+ if arg in ['help']:
+ os.execlp('man', 'man', 'qmp-%s' % command)
+ return 1
+
+ arguments[arg] = value
+
+ rsp = do_command(srv, command, **arguments)
+ print_response(rsp)
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
new file mode 100755
index 0000000..73cb3b6
--- /dev/null
+++ b/scripts/qmp/qmp-shell
@@ -0,0 +1,286 @@
+#!/usr/bin/python
+#
+# Low-level QEMU shell on top of QMP.
+#
+# Copyright (C) 2009, 2010 Red Hat Inc.
+#
+# Authors:
+# Luiz Capitulino <lcapitulino@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+# Usage:
+#
+# Start QEMU with:
+#
+# # qemu [...] -qmp unix:./qmp-sock,server
+#
+# Run the shell:
+#
+# $ qmp-shell ./qmp-sock
+#
+# Commands have the following format:
+#
+# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+#
+# For example:
+#
+# (QEMU) device_add driver=e1000 id=net1
+# {u'return': {}}
+# (QEMU)
+
+import qmp
+import readline
+import sys
+import pprint
+
+class QMPCompleter(list):
+ def complete(self, text, state):
+ for cmd in self:
+ if cmd.startswith(text):
+ if not state:
+ return cmd
+ else:
+ state -= 1
+
+class QMPShellError(Exception):
+ pass
+
+class QMPShellBadPort(QMPShellError):
+ pass
+
+# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
+# _execute_cmd()). Let's design a better one.
+class QMPShell(qmp.QEMUMonitorProtocol):
+ def __init__(self, address, pp=None):
+ qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
+ self._greeting = None
+ self._completer = None
+ self._pp = pp
+
+ def __get_address(self, arg):
+ """
+ Figure out if the argument is in the port:host form, if it's not it's
+ probably a file path.
+ """
+ addr = arg.split(':')
+ if len(addr) == 2:
+ try:
+ port = int(addr[1])
+ except ValueError:
+ raise QMPShellBadPort
+ return ( addr[0], port )
+ # socket path
+ return arg
+
+ def _fill_completion(self):
+ for cmd in self.cmd('query-commands')['return']:
+ self._completer.append(cmd['name'])
+
+ def __completer_setup(self):
+ self._completer = QMPCompleter()
+ self._fill_completion()
+ readline.set_completer(self._completer.complete)
+ readline.parse_and_bind("tab: complete")
+ # XXX: default delimiters conflict with some command names (eg. query-),
+ # clearing everything as it doesn't seem to matter
+ readline.set_completer_delims('')
+
+ def __build_cmd(self, cmdline):
+ """
+ Build a QMP input object from a user provided command-line in the
+ following format:
+
+ < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+ """
+ cmdargs = cmdline.split()
+ qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+ for arg in cmdargs[1:]:
+ opt = arg.split('=')
+ try:
+ if(len(opt) > 2):
+ opt[1] = '='.join(opt[1:])
+ value = int(opt[1])
+ except ValueError:
+ if opt[1] == 'true':
+ value = True
+ elif opt[1] == 'false':
+ value = False
+ else:
+ value = opt[1]
+ qmpcmd['arguments'][opt[0]] = value
+ return qmpcmd
+
+ def _execute_cmd(self, cmdline):
+ try:
+ qmpcmd = self.__build_cmd(cmdline)
+ except:
+ print 'command format: <command-name> ',
+ print '[arg-name1=arg1] ... [arg-nameN=argN]'
+ return True
+ resp = self.cmd_obj(qmpcmd)
+ if resp is None:
+ print 'Disconnected'
+ return False
+
+ if self._pp is not None:
+ self._pp.pprint(resp)
+ else:
+ print resp
+ return True
+
+ def connect(self):
+ self._greeting = qmp.QEMUMonitorProtocol.connect(self)
+ self.__completer_setup()
+
+ def show_banner(self, msg='Welcome to the QMP low-level shell!'):
+ print msg
+ version = self._greeting['QMP']['version']['qemu']
+ print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
+
+ def read_exec_command(self, prompt):
+ """
+ Read and execute a command.
+
+ @return True if execution was ok, return False if disconnected.
+ """
+ try:
+ cmdline = raw_input(prompt)
+ except EOFError:
+ print
+ return False
+ if cmdline == '':
+ for ev in self.get_events():
+ print ev
+ self.clear_events()
+ return True
+ else:
+ return self._execute_cmd(cmdline)
+
+class HMPShell(QMPShell):
+ def __init__(self, address):
+ QMPShell.__init__(self, address)
+ self.__cpu_index = 0
+
+ def __cmd_completion(self):
+ for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
+ if cmd and cmd[0] != '[' and cmd[0] != '\t':
+ name = cmd.split()[0] # drop help text
+ if name == 'info':
+ continue
+ if name.find('|') != -1:
+ # Command in the form 'foobar|f' or 'f|foobar', take the
+ # full name
+ opt = name.split('|')
+ if len(opt[0]) == 1:
+ name = opt[1]
+ else:
+ name = opt[0]
+ self._completer.append(name)
+ self._completer.append('help ' + name) # help completion
+
+ def __info_completion(self):
+ for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
+ if cmd:
+ self._completer.append('info ' + cmd.split()[1])
+
+ def __other_completion(self):
+ # special cases
+ self._completer.append('help info')
+
+ def _fill_completion(self):
+ self.__cmd_completion()
+ self.__info_completion()
+ self.__other_completion()
+
+ def __cmd_passthrough(self, cmdline, cpu_index = 0):
+ return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
+ { 'command-line': cmdline,
+ 'cpu-index': cpu_index } })
+
+ def _execute_cmd(self, cmdline):
+ if cmdline.split()[0] == "cpu":
+ # trap the cpu command, it requires special setting
+ try:
+ idx = int(cmdline.split()[1])
+ if not 'return' in self.__cmd_passthrough('info version', idx):
+ print 'bad CPU index'
+ return True
+ self.__cpu_index = idx
+ except ValueError:
+ print 'cpu command takes an integer argument'
+ return True
+ resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
+ if resp is None:
+ print 'Disconnected'
+ return False
+ assert 'return' in resp or 'error' in resp
+ if 'return' in resp:
+ # Success
+ if len(resp['return']) > 0:
+ print resp['return'],
+ else:
+ # Error
+ print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
+ return True
+
+ def show_banner(self):
+ QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
+
+def die(msg):
+ sys.stderr.write('ERROR: %s\n' % msg)
+ sys.exit(1)
+
+def fail_cmdline(option=None):
+ if option:
+ sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
+ sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
+ sys.exit(1)
+
+def main():
+ addr = ''
+ qemu = None
+ hmp = False
+ pp = None
+
+ try:
+ for arg in sys.argv[1:]:
+ if arg == "-H":
+ if qemu is not None:
+ fail_cmdline(arg)
+ hmp = True
+ elif arg == "-p":
+ if pp is not None:
+ fail_cmdline(arg)
+ pp = pprint.PrettyPrinter(indent=4)
+ else:
+ if qemu is not None:
+ fail_cmdline(arg)
+ if hmp:
+ qemu = HMPShell(arg)
+ else:
+ qemu = QMPShell(arg, pp)
+ addr = arg
+
+ if qemu is None:
+ fail_cmdline()
+ except QMPShellBadPort:
+ die('bad port number in command-line')
+
+ try:
+ qemu.connect()
+ except qmp.QMPConnectError:
+ die('Didn\'t get QMP greeting message')
+ except qmp.QMPCapabilitiesError:
+ die('Could not negotiate capabilities')
+ except qemu.error:
+ die('Could not connect to %s' % addr)
+
+ qemu.show_banner()
+ while qemu.read_exec_command('(QEMU) '):
+ pass
+ qemu.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/qmp/qmp.py b/scripts/qmp/qmp.py
new file mode 100644
index 0000000..c551df1
--- /dev/null
+++ b/scripts/qmp/qmp.py
@@ -0,0 +1,190 @@
+# QEMU Monitor Protocol Python class
+#
+# Copyright (C) 2009, 2010 Red Hat Inc.
+#
+# Authors:
+# Luiz Capitulino <lcapitulino@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+
+import json
+import errno
+import socket
+
+class QMPError(Exception):
+ pass
+
+class QMPConnectError(QMPError):
+ pass
+
+class QMPCapabilitiesError(QMPError):
+ pass
+
+class QEMUMonitorProtocol:
+ def __init__(self, address, server=False):
+ """
+ Create a QEMUMonitorProtocol class.
+
+ @param address: QEMU address, can be either a unix socket path (string)
+ or a tuple in the form ( address, port ) for a TCP
+ connection
+ @param server: server mode listens on the socket (bool)
+ @raise socket.error on socket connection errors
+ @note No connection is established, this is done by the connect() or
+ accept() methods
+ """
+ self.__events = []
+ self.__address = address
+ self.__sock = self.__get_sock()
+ if server:
+ self.__sock.bind(self.__address)
+ self.__sock.listen(1)
+
+ def __get_sock(self):
+ if isinstance(self.__address, tuple):
+ family = socket.AF_INET
+ else:
+ family = socket.AF_UNIX
+ return socket.socket(family, socket.SOCK_STREAM)
+
+ def __negotiate_capabilities(self):
+ greeting = self.__json_read()
+ if greeting is None or not greeting.has_key('QMP'):
+ raise QMPConnectError
+ # Greeting seems ok, negotiate capabilities
+ resp = self.cmd('qmp_capabilities')
+ if "return" in resp:
+ return greeting
+ raise QMPCapabilitiesError
+
+ def __json_read(self, only_event=False):
+ while True:
+ data = self.__sockfile.readline()
+ if not data:
+ return
+ resp = json.loads(data)
+ if 'event' in resp:
+ self.__events.append(resp)
+ if not only_event:
+ continue
+ return resp
+
+ error = socket.error
+
+ def connect(self, negotiate=True):
+ """
+ Connect to the QMP Monitor and perform capabilities negotiation.
+
+ @return QMP greeting dict
+ @raise socket.error on socket connection errors
+ @raise QMPConnectError if the greeting is not received
+ @raise QMPCapabilitiesError if fails to negotiate capabilities
+ """
+ self.__sock.connect(self.__address)
+ self.__sockfile = self.__sock.makefile()
+ if negotiate:
+ return self.__negotiate_capabilities()
+
+ def accept(self):
+ """
+ Await connection from QMP Monitor and perform capabilities negotiation.
+
+ @return QMP greeting dict
+ @raise socket.error on socket connection errors
+ @raise QMPConnectError if the greeting is not received
+ @raise QMPCapabilitiesError if fails to negotiate capabilities
+ """
+ self.__sock, _ = self.__sock.accept()
+ self.__sockfile = self.__sock.makefile()
+ return self.__negotiate_capabilities()
+
+ def cmd_obj(self, qmp_cmd):
+ """
+ Send a QMP command to the QMP Monitor.
+
+ @param qmp_cmd: QMP command to be sent as a Python dict
+ @return QMP response as a Python dict or None if the connection has
+ been closed
+ """
+ try:
+ self.__sock.sendall(json.dumps(qmp_cmd))
+ except socket.error, err:
+ if err[0] == errno.EPIPE:
+ return
+ raise socket.error(err)
+ return self.__json_read()
+
+ def cmd(self, name, args=None, id=None):
+ """
+ Build a QMP command and send it to the QMP Monitor.
+
+ @param name: command name (string)
+ @param args: command arguments (dict)
+ @param id: command id (dict, list, string or int)
+ """
+ qmp_cmd = { 'execute': name }
+ if args:
+ qmp_cmd['arguments'] = args
+ if id:
+ qmp_cmd['id'] = id
+ return self.cmd_obj(qmp_cmd)
+
+ def command(self, cmd, **kwds):
+ ret = self.cmd(cmd, kwds)
+ if ret.has_key('error'):
+ raise Exception(ret['error']['desc'])
+ return ret['return']
+
+ def pull_event(self, wait=False):
+ """
+ Get and delete the first available QMP event.
+
+ @param wait: block until an event is available (bool)
+ """
+ self.__sock.setblocking(0)
+ try:
+ self.__json_read()
+ except socket.error, err:
+ if err[0] == errno.EAGAIN:
+ # No data available
+ pass
+ self.__sock.setblocking(1)
+ if not self.__events and wait:
+ self.__json_read(only_event=True)
+ event = self.__events[0]
+ del self.__events[0]
+ return event
+
+ def get_events(self, wait=False):
+ """
+ Get a list of available QMP events.
+
+ @param wait: block until an event is available (bool)
+ """
+ self.__sock.setblocking(0)
+ try:
+ self.__json_read()
+ except socket.error, err:
+ if err[0] == errno.EAGAIN:
+ # No data available
+ pass
+ self.__sock.setblocking(1)
+ if not self.__events and wait:
+ self.__json_read(only_event=True)
+ return self.__events
+
+ def clear_events(self):
+ """
+ Clear current list of pending events.
+ """
+ self.__events = []
+
+ def close(self):
+ self.__sock.close()
+ self.__sockfile.close()
+
+ timeout = socket.timeout
+
+ def settimeout(self, timeout):
+ self.__sock.settimeout(timeout)
diff --git a/scripts/qmp/qom-fuse b/scripts/qmp/qom-fuse
new file mode 100755
index 0000000..5c6754a
--- /dev/null
+++ b/scripts/qmp/qom-fuse
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later. See
+# the COPYING file in the top-level directory.
+##
+
+import fuse, stat
+from fuse import Fuse
+import os, posix
+from errno import *
+from qmp import QEMUMonitorProtocol
+
+fuse.fuse_python_api = (0, 2)
+
+class QOMFS(Fuse):
+ def __init__(self, qmp, *args, **kwds):
+ Fuse.__init__(self, *args, **kwds)
+ self.qmp = qmp
+ self.qmp.connect()
+ self.ino_map = {}
+ self.ino_count = 1
+
+ def get_ino(self, path):
+ if self.ino_map.has_key(path):
+ return self.ino_map[path]
+ self.ino_map[path] = self.ino_count
+ self.ino_count += 1
+ return self.ino_map[path]
+
+ def is_object(self, path):
+ try:
+ items = self.qmp.command('qom-list', path=path)
+ return True
+ except:
+ return False
+
+ def is_property(self, path):
+ try:
+ path, prop = path.rsplit('/', 1)
+ for item in self.qmp.command('qom-list', path=path):
+ if item['name'] == prop:
+ return True
+ return False
+ except:
+ return False
+
+ def is_link(self, path):
+ try:
+ path, prop = path.rsplit('/', 1)
+ for item in self.qmp.command('qom-list', path=path):
+ if item['name'] == prop:
+ if item['type'].startswith('link<'):
+ return True
+ return False
+ return False
+ except:
+ return False
+
+ def read(self, path, length, offset):
+ if not self.is_property(path):
+ return -ENOENT
+
+ path, prop = path.rsplit('/', 1)
+ try:
+ data = str(self.qmp.command('qom-get', path=path, property=prop))
+ data += '\n' # make values shell friendly
+ except:
+ return -EPERM
+
+ if offset > len(data):
+ return ''
+
+ return str(data[offset:][:length])
+
+ def readlink(self, path):
+ if not self.is_link(path):
+ return False
+ path, prop = path.rsplit('/', 1)
+ prefix = '/'.join(['..'] * (len(path.split('/')) - 1))
+ return prefix + str(self.qmp.command('qom-get', path=path,
+ property=prop))
+
+ def getattr(self, path):
+ if self.is_link(path):
+ value = posix.stat_result((0755 | stat.S_IFLNK,
+ self.get_ino(path),
+ 0,
+ 2,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ elif self.is_object(path):
+ value = posix.stat_result((0755 | stat.S_IFDIR,
+ self.get_ino(path),
+ 0,
+ 2,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ elif self.is_property(path):
+ value = posix.stat_result((0644 | stat.S_IFREG,
+ self.get_ino(path),
+ 0,
+ 1,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ else:
+ value = -ENOENT
+ return value
+
+ def readdir(self, path, offset):
+ yield fuse.Direntry('.')
+ yield fuse.Direntry('..')
+ for item in self.qmp.command('qom-list', path=path):
+ yield fuse.Direntry(str(item['name']))
+
+if __name__ == '__main__':
+ import sys, os
+
+ fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
+ fs.main(sys.argv)
diff --git a/scripts/qmp/qom-get b/scripts/qmp/qom-get
new file mode 100755
index 0000000..0172c69
--- /dev/null
+++ b/scripts/qmp/qom-get
@@ -0,0 +1,67 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later. See
+# the COPYING file in the top-level directory.
+##
+
+import sys
+import os
+from qmp import QEMUMonitorProtocol
+
+cmd, args = sys.argv[0], sys.argv[1:]
+socket_path = None
+path = None
+prop = None
+
+def usage():
+ return '''environment variables:
+ QMP_SOCKET=<path | addr:port>
+usage:
+ %s [-h] [-s <QMP socket path | addr:port>] <path>.<property>
+''' % cmd
+
+def usage_error(error_msg = "unspecified error"):
+ sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
+ exit(1)
+
+if len(args) > 0:
+ if args[0] == "-h":
+ print usage()
+ exit(0);
+ elif args[0] == "-s":
+ try:
+ socket_path = args[1]
+ except:
+ usage_error("missing argument: QMP socket path or address");
+ args = args[2:]
+
+if not socket_path:
+ if os.environ.has_key('QMP_SOCKET'):
+ socket_path = os.environ['QMP_SOCKET']
+ else:
+ usage_error("no QMP socket path or address given");
+
+if len(args) > 0:
+ try:
+ path, prop = args[0].rsplit('.', 1)
+ except:
+ usage_error("invalid format for path/property/value")
+else:
+ usage_error("not enough arguments")
+
+srv = QEMUMonitorProtocol(socket_path)
+srv.connect()
+
+rsp = srv.command('qom-get', path=path, property=prop)
+if type(rsp) == dict:
+ for i in rsp.keys():
+ print '%s: %s' % (i, rsp[i])
+else:
+ print rsp
diff --git a/scripts/qmp/qom-list b/scripts/qmp/qom-list
new file mode 100755
index 0000000..1e7cc6c
--- /dev/null
+++ b/scripts/qmp/qom-list
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later. See
+# the COPYING file in the top-level directory.
+##
+
+import sys
+import os
+from qmp import QEMUMonitorProtocol
+
+cmd, args = sys.argv[0], sys.argv[1:]
+socket_path = None
+path = None
+prop = None
+
+def usage():
+ return '''environment variables:
+ QMP_SOCKET=<path | addr:port>
+usage:
+ %s [-h] [-s <QMP socket path | addr:port>] [<path>]
+''' % cmd
+
+def usage_error(error_msg = "unspecified error"):
+ sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
+ exit(1)
+
+if len(args) > 0:
+ if args[0] == "-h":
+ print usage()
+ exit(0);
+ elif args[0] == "-s":
+ try:
+ socket_path = args[1]
+ except:
+ usage_error("missing argument: QMP socket path or address");
+ args = args[2:]
+
+if not socket_path:
+ if os.environ.has_key('QMP_SOCKET'):
+ socket_path = os.environ['QMP_SOCKET']
+ else:
+ usage_error("no QMP socket path or address given");
+
+srv = QEMUMonitorProtocol(socket_path)
+srv.connect()
+
+if len(args) == 0:
+ print '/'
+ sys.exit(0)
+
+for item in srv.command('qom-list', path=args[0]):
+ if item['type'].startswith('child<'):
+ print '%s/' % item['name']
+ elif item['type'].startswith('link<'):
+ print '@%s/' % item['name']
+ else:
+ print '%s' % item['name']
diff --git a/scripts/qmp/qom-set b/scripts/qmp/qom-set
new file mode 100755
index 0000000..54ecfec
--- /dev/null
+++ b/scripts/qmp/qom-set
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later. See
+# the COPYING file in the top-level directory.
+##
+
+import sys
+import os
+from qmp import QEMUMonitorProtocol
+
+cmd, args = sys.argv[0], sys.argv[1:]
+socket_path = None
+path = None
+prop = None
+value = None
+
+def usage():
+ return '''environment variables:
+ QMP_SOCKET=<path | addr:port>
+usage:
+ %s [-h] [-s <QMP socket path | addr:port>] <path>.<property> <value>
+''' % cmd
+
+def usage_error(error_msg = "unspecified error"):
+ sys.stderr.write('%s\nERROR: %s\n' % (usage(), error_msg))
+ exit(1)
+
+if len(args) > 0:
+ if args[0] == "-h":
+ print usage()
+ exit(0);
+ elif args[0] == "-s":
+ try:
+ socket_path = args[1]
+ except:
+ usage_error("missing argument: QMP socket path or address");
+ args = args[2:]
+
+if not socket_path:
+ if os.environ.has_key('QMP_SOCKET'):
+ socket_path = os.environ['QMP_SOCKET']
+ else:
+ usage_error("no QMP socket path or address given");
+
+if len(args) > 1:
+ try:
+ path, prop = args[0].rsplit('.', 1)
+ except:
+ usage_error("invalid format for path/property/value")
+ value = args[1]
+else:
+ usage_error("not enough arguments")
+
+srv = QEMUMonitorProtocol(socket_path)
+srv.connect()
+
+print srv.command('qom-set', path=path, property=prop, value=sys.argv[2])
--
1.8.1.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp
2013-09-11 20:52 ` [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp Luiz Capitulino
@ 2013-09-11 22:08 ` Eric Blake
2013-09-11 22:13 ` Eric Blake
0 siblings, 1 reply; 20+ messages in thread
From: Eric Blake @ 2013-09-11 22:08 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel, armbru
[-- Attachment #1: Type: text/plain, Size: 4239 bytes --]
On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> Populate it with all scripts stored in QMP/.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
> QMP/qemu-ga-client | 299 ---------------------------------------------
> QMP/qmp | 126 -------------------
> QMP/qmp-shell | 286 -------------------------------------------
> QMP/qmp.py | 190 ----------------------------
> QMP/qom-fuse | 138 ---------------------
> QMP/qom-get | 67 ----------
> QMP/qom-list | 64 ----------
> QMP/qom-set | 64 ----------
> scripts/qmp/qemu-ga-client | 299 +++++++++++++++++++++++++++++++++++++++++++++
> scripts/qmp/qmp | 126 +++++++++++++++++++
> scripts/qmp/qmp-shell | 286 +++++++++++++++++++++++++++++++++++++++++++
> scripts/qmp/qmp.py | 190 ++++++++++++++++++++++++++++
> scripts/qmp/qom-fuse | 138 +++++++++++++++++++++
> scripts/qmp/qom-get | 67 ++++++++++
> scripts/qmp/qom-list | 64 ++++++++++
> scripts/qmp/qom-set | 64 ++++++++++
> 16 files changed, 1234 insertions(+), 1234 deletions(-)
> delete mode 100755 QMP/qemu-ga-client
> delete mode 100755 QMP/qmp
> delete mode 100755 QMP/qmp-shell
> delete mode 100644 QMP/qmp.py
> delete mode 100755 QMP/qom-fuse
> delete mode 100755 QMP/qom-get
> delete mode 100755 QMP/qom-list
> delete mode 100755 QMP/qom-set
> create mode 100755 scripts/qmp/qemu-ga-client
> create mode 100755 scripts/qmp/qmp
> create mode 100755 scripts/qmp/qmp-shell
> create mode 100644 scripts/qmp/qmp.py
> create mode 100755 scripts/qmp/qom-fuse
> create mode 100755 scripts/qmp/qom-get
> create mode 100755 scripts/qmp/qom-list
> create mode 100755 scripts/qmp/qom-set
Reviewed-by: Eric Blake <eblake@redhat.com>
Repeat after me:
git config diff.renames true
at which point, this commit is much more compact and reviewable:
From c2957616df8bfa2066cbb375de106a45b5a80ae4 Mon Sep 17 00:00:00 2001
From: Luiz Capitulino <lcapitulino@redhat.com>
Date: Wed, 11 Sep 2013 16:52:12 -0400
Subject: [PATCH] QMP: add scripts/qmp
Populate it with all scripts stored in QMP/.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
{QMP => scripts/qmp}/qemu-ga-client | 0
{QMP => scripts/qmp}/qmp | 0
{QMP => scripts/qmp}/qmp-shell | 0
{QMP => scripts/qmp}/qmp.py | 0
{QMP => scripts/qmp}/qom-fuse | 0
{QMP => scripts/qmp}/qom-get | 0
{QMP => scripts/qmp}/qom-list | 0
{QMP => scripts/qmp}/qom-set | 0
8 files changed, 0 insertions(+), 0 deletions(-)
rename {QMP => scripts/qmp}/qemu-ga-client (100%)
rename {QMP => scripts/qmp}/qmp (100%)
rename {QMP => scripts/qmp}/qmp-shell (100%)
rename {QMP => scripts/qmp}/qmp.py (100%)
rename {QMP => scripts/qmp}/qom-fuse (100%)
rename {QMP => scripts/qmp}/qom-get (100%)
rename {QMP => scripts/qmp}/qom-list (100%)
rename {QMP => scripts/qmp}/qom-set (100%)
diff --git a/QMP/qemu-ga-client b/scripts/qmp/qemu-ga-client
similarity index 100%
rename from QMP/qemu-ga-client
rename to scripts/qmp/qemu-ga-client
diff --git a/QMP/qmp b/scripts/qmp/qmp
similarity index 100%
rename from QMP/qmp
rename to scripts/qmp/qmp
diff --git a/QMP/qmp-shell b/scripts/qmp/qmp-shell
similarity index 100%
rename from QMP/qmp-shell
rename to scripts/qmp/qmp-shell
diff --git a/QMP/qmp.py b/scripts/qmp/qmp.py
similarity index 100%
rename from QMP/qmp.py
rename to scripts/qmp/qmp.py
diff --git a/QMP/qom-fuse b/scripts/qmp/qom-fuse
similarity index 100%
rename from QMP/qom-fuse
rename to scripts/qmp/qom-fuse
diff --git a/QMP/qom-get b/scripts/qmp/qom-get
similarity index 100%
rename from QMP/qom-get
rename to scripts/qmp/qom-get
diff --git a/QMP/qom-list b/scripts/qmp/qom-list
similarity index 100%
rename from QMP/qom-list
rename to scripts/qmp/qom-list
diff --git a/QMP/qom-set b/scripts/qmp/qom-set
similarity index 100%
rename from QMP/qom-set
rename to scripts/qmp/qom-set
--
1.8.3.1
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp
2013-09-11 22:08 ` Eric Blake
@ 2013-09-11 22:13 ` Eric Blake
2013-09-13 17:52 ` Luiz Capitulino
0 siblings, 1 reply; 20+ messages in thread
From: Eric Blake @ 2013-09-11 22:13 UTC (permalink / raw)
Cc: armbru, qemu-devel, Luiz Capitulino
[-- Attachment #1: Type: text/plain, Size: 902 bytes --]
On 09/11/2013 04:08 PM, Eric Blake wrote:
> On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
>> Populate it with all scripts stored in QMP/.
>>
>> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
> Repeat after me:
> git config diff.renames true
>
> at which point, this commit is much more compact and reviewable:
>
Oh, and while testing your patch:
<stdin>:1854: trailing whitespace.
<stdin>:2054: trailing whitespace.
#
warning: 2 lines add whitespace errors.
One instance from qmp-shell; the other from qmp.py. It's okay if you
touch those up as part of this rename (again, the diff.renames true bit
will highlight those two changes, rather than showing the complete file
as a delete and addition).
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp
2013-09-11 22:13 ` Eric Blake
@ 2013-09-13 17:52 ` Luiz Capitulino
0 siblings, 0 replies; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-13 17:52 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, armbru
On Wed, 11 Sep 2013 16:13:32 -0600
Eric Blake <eblake@redhat.com> wrote:
> On 09/11/2013 04:08 PM, Eric Blake wrote:
> > On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> >> Populate it with all scripts stored in QMP/.
> >>
> >> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
>
> > Reviewed-by: Eric Blake <eblake@redhat.com>
> >
> > Repeat after me:
> > git config diff.renames true
> >
> > at which point, this commit is much more compact and reviewable:
Done.
> Oh, and while testing your patch:
>
> <stdin>:1854: trailing whitespace.
>
> <stdin>:2054: trailing whitespace.
> #
> warning: 2 lines add whitespace errors.
>
> One instance from qmp-shell; the other from qmp.py. It's okay if you
> touch those up as part of this rename (again, the diff.renames true bit
> will highlight those two changes, rather than showing the complete file
> as a delete and addition).
Fixed.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 2/6] QMP: fix qmp-commands.txt generation path
2013-09-11 20:52 [Qemu-devel] [PATCH 0/6] QMP: re-organize documentation Luiz Capitulino
2013-09-11 20:52 ` [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp Luiz Capitulino
@ 2013-09-11 20:52 ` Luiz Capitulino
2013-09-11 22:09 ` Eric Blake
2013-09-11 20:52 ` [Qemu-devel] [PATCH 3/6] QMP: QMP/ -> docs/qmp/ Luiz Capitulino
` (3 subsequent siblings)
5 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-11 20:52 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru
This file should be generated in the BUILD_DIR, as all other docs.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
Makefile | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index 806946e..4a147b0 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,7 @@ LIBS+=-lz $(LIBS_TOOLS)
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
ifdef BUILD_DOCS
-DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
+DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qmp-commands.txt
ifdef CONFIG_VIRTFS
DOCS+=fsdev/virtfs-proxy-helper.1
endif
@@ -303,7 +303,7 @@ endif
install-doc: $(DOCS)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
- $(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
+ $(INSTALL_DATA) qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
@@ -397,7 +397,7 @@ qemu-options.texi: $(SRC_PATH)/qemu-options.hx
qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
-QMP/qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
+qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@," GEN $@")
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
--
1.8.1.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 3/6] QMP: QMP/ -> docs/qmp/
2013-09-11 20:52 [Qemu-devel] [PATCH 0/6] QMP: re-organize documentation Luiz Capitulino
2013-09-11 20:52 ` [Qemu-devel] [PATCH 1/6] QMP: add scripts/qmp Luiz Capitulino
2013-09-11 20:52 ` [Qemu-devel] [PATCH 2/6] QMP: fix qmp-commands.txt generation path Luiz Capitulino
@ 2013-09-11 20:52 ` Luiz Capitulino
2013-09-11 22:15 ` Eric Blake
2013-09-11 20:52 ` [Qemu-devel] [PATCH 4/6] QMP: Update README file Luiz Capitulino
` (2 subsequent siblings)
5 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-11 20:52 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
QMP/README | 88 ---------
QMP/qmp-events.txt | 480 ------------------------------------------------
QMP/qmp-spec.txt | 282 ----------------------------
docs/qmp/README | 88 +++++++++
docs/qmp/qmp-events.txt | 480 ++++++++++++++++++++++++++++++++++++++++++++++++
docs/qmp/qmp-spec.txt | 282 ++++++++++++++++++++++++++++
6 files changed, 850 insertions(+), 850 deletions(-)
delete mode 100644 QMP/README
delete mode 100644 QMP/qmp-events.txt
delete mode 100644 QMP/qmp-spec.txt
create mode 100644 docs/qmp/README
create mode 100644 docs/qmp/qmp-events.txt
create mode 100644 docs/qmp/qmp-spec.txt
diff --git a/QMP/README b/QMP/README
deleted file mode 100644
index c95a08c..0000000
--- a/QMP/README
+++ /dev/null
@@ -1,88 +0,0 @@
- QEMU Monitor Protocol
- =====================
-
-Introduction
--------------
-
-The QEMU Monitor Protocol (QMP) allows applications to communicate with
-QEMU's Monitor.
-
-QMP is JSON[1] based and currently has the following features:
-
-- Lightweight, text-based, easy to parse data format
-- Asynchronous messages support (ie. events)
-- Capabilities Negotiation
-
-For detailed information on QMP's usage, please, refer to the following files:
-
-o qmp-spec.txt QEMU Monitor Protocol current specification
-o qmp-commands.txt QMP supported commands (auto-generated at build-time)
-o qmp-events.txt List of available asynchronous events
-
-There is also a simple Python script called 'qmp-shell' available.
-
-IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
-section in the qmp-commands.txt file before making any serious use of QMP.
-
-
-[1] http://www.json.org
-
-Usage
------
-
-To enable QMP, you need a QEMU monitor instance in "control mode". There are
-two ways of doing this.
-
-The simplest one is using the '-qmp' command-line option. The following
-example makes QMP available on localhost port 4444:
-
- $ qemu [...] -qmp tcp:localhost:4444,server
-
-However, in order to have more complex combinations, like multiple monitors,
-the '-mon' command-line option should be used along with the '-chardev' one.
-For instance, the following example creates one user monitor on stdio and one
-QMP monitor on localhost port 4444.
-
- $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
- -chardev socket,id=mon1,host=localhost,port=4444,server \
- -mon chardev=mon1,mode=control
-
-Please, refer to QEMU's manpage for more information.
-
-Simple Testing
---------------
-
-To manually test QMP one can connect with telnet and issue commands by hand:
-
-$ telnet localhost 4444
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
-{ "execute": "qmp_capabilities" }
-{"return": {}}
-{ "execute": "query-version" }
-{"return": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}}
-
-Development Process
--------------------
-
-When changing QMP's interface (by adding new commands, events or modifying
-existing ones) it's mandatory to update the relevant documentation, which is
-one (or more) of the files listed in the 'Introduction' section*.
-
-Also, it's strongly recommended to send the documentation patch first, before
-doing any code change. This is so because:
-
- 1. Avoids the code dictating the interface
-
- 2. Review can improve your interface. Letting that happen before
- you implement it can save you work.
-
-* The qmp-commands.txt file is generated from the qmp-commands.hx one, which
- is the file that should be edited.
-
-Homepage
---------
-
-http://wiki.qemu.org/QMP
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
deleted file mode 100644
index 39b6016..0000000
--- a/QMP/qmp-events.txt
+++ /dev/null
@@ -1,480 +0,0 @@
- QEMU Monitor Protocol Events
- ============================
-
-BALLOON_CHANGE
---------------
-
-Emitted when the guest changes the actual BALLOON level. This
-value is equivalent to the 'actual' field return by the
-'query-balloon' command
-
-Data:
-
-- "actual": actual level of the guest memory balloon in bytes (json-number)
-
-Example:
-
-{ "event": "BALLOON_CHANGE",
- "data": { "actual": 944766976 },
- "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-
-BLOCK_IO_ERROR
---------------
-
-Emitted when a disk I/O error occurs.
-
-Data:
-
-- "device": device name (json-string)
-- "operation": I/O operation (json-string, "read" or "write")
-- "action": action that has been taken, it's one of the following (json-string):
- "ignore": error has been ignored
- "report": error has been reported to the device
- "stop": error caused VM to be stopped
-
-Example:
-
-{ "event": "BLOCK_IO_ERROR",
- "data": { "device": "ide0-hd1",
- "operation": "write",
- "action": "stop" },
- "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-Note: If action is "stop", a STOP event will eventually follow the
-BLOCK_IO_ERROR event.
-
-BLOCK_JOB_CANCELLED
--------------------
-
-Emitted when a block job has been cancelled.
-
-Data:
-
-- "type": Job type (json-string; "stream" for image streaming
- "commit" for block commit)
-- "device": Device name (json-string)
-- "len": Maximum progress value (json-int)
-- "offset": Current progress value (json-int)
- On success this is equal to len.
- On failure this is less than len.
-- "speed": Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_CANCELLED",
- "data": { "type": "stream", "device": "virtio-disk0",
- "len": 10737418240, "offset": 134217728,
- "speed": 0 },
- "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-BLOCK_JOB_COMPLETED
--------------------
-
-Emitted when a block job has completed.
-
-Data:
-
-- "type": Job type (json-string; "stream" for image streaming
- "commit" for block commit)
-- "device": Device name (json-string)
-- "len": Maximum progress value (json-int)
-- "offset": Current progress value (json-int)
- On success this is equal to len.
- On failure this is less than len.
-- "speed": Rate limit, bytes per second (json-int)
-- "error": Error message (json-string, optional)
- Only present on failure. This field contains a human-readable
- error message. There are no semantics other than that streaming
- has failed and clients should not try to interpret the error
- string.
-
-Example:
-
-{ "event": "BLOCK_JOB_COMPLETED",
- "data": { "type": "stream", "device": "virtio-disk0",
- "len": 10737418240, "offset": 10737418240,
- "speed": 0 },
- "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-BLOCK_JOB_ERROR
----------------
-
-Emitted when a block job encounters an error.
-
-Data:
-
-- "device": device name (json-string)
-- "operation": I/O operation (json-string, "read" or "write")
-- "action": action that has been taken, it's one of the following (json-string):
- "ignore": error has been ignored, the job may fail later
- "report": error will be reported and the job canceled
- "stop": error caused job to be paused
-
-Example:
-
-{ "event": "BLOCK_JOB_ERROR",
- "data": { "device": "ide0-hd1",
- "operation": "write",
- "action": "stop" },
- "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-BLOCK_JOB_READY
----------------
-
-Emitted when a block job is ready to complete.
-
-Data:
-
-- "device": device name (json-string)
-
-Example:
-
-{ "event": "BLOCK_JOB_READY",
- "data": { "device": "ide0-hd1" },
- "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
-event.
-
-DEVICE_DELETED
------------------
-
-Emitted whenever the device removal completion is acknowledged
-by the guest.
-At this point, it's safe to reuse the specified device ID.
-Device removal can be initiated by the guest or by HMP/QMP commands.
-
-Data:
-
-- "device": device name (json-string, optional)
-- "path": device path (json-string)
-
-{ "event": "DEVICE_DELETED",
- "data": { "device": "virtio-net-pci-0",
- "path": "/machine/peripheral/virtio-net-pci-0" },
- "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-DEVICE_TRAY_MOVED
------------------
-
-It's emitted whenever the tray of a removable device is moved by the guest
-or by HMP/QMP commands.
-
-Data:
-
-- "device": device name (json-string)
-- "tray-open": true if the tray has been opened or false if it has been closed
- (json-bool)
-
-{ "event": "DEVICE_TRAY_MOVED",
- "data": { "device": "ide1-cd0",
- "tray-open": true
- },
- "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-NIC_RX_FILTER_CHANGED
------------------
-
-The event is emitted once until the query command is executed,
-the first event will always be emitted.
-
-Data:
-
-- "name": net client name (json-string)
-- "path": device path (json-string)
-
-{ "event": "NIC_RX_FILTER_CHANGED",
- "data": { "name": "vnet0",
- "path": "/machine/peripheral/vnet0/virtio-backend" },
- "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
-}
-
-RESET
------
-
-Emitted when the Virtual Machine is reseted.
-
-Data: None.
-
-Example:
-
-{ "event": "RESET",
- "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
-
-RESUME
-------
-
-Emitted when the Virtual Machine resumes execution.
-
-Data: None.
-
-Example:
-
-{ "event": "RESUME",
- "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
-
-RTC_CHANGE
-----------
-
-Emitted when the guest changes the RTC time.
-
-Data:
-
-- "offset": Offset between base RTC clock (as specified by -rtc base), and
-new RTC clock value (json-number)
-
-Example:
-
-{ "event": "RTC_CHANGE",
- "data": { "offset": 78 },
- "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-
-SHUTDOWN
---------
-
-Emitted when the Virtual Machine is powered down.
-
-Data: None.
-
-Example:
-
-{ "event": "SHUTDOWN",
- "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
-
-Note: If the command-line option "-no-shutdown" has been specified, a STOP
-event will eventually follow the SHUTDOWN event.
-
-SPICE_CONNECTED, SPICE_DISCONNECTED
------------------------------------
-
-Emitted when a SPICE client connects or disconnects.
-
-Data:
-
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
- "event": "SPICE_CONNECTED",
- "data": {
- "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
- "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-SPICE_INITIALIZED
------------------
-
-Emitted after initial handshake and authentication takes place (if any)
-and the SPICE channel is up'n'running
-
-Data:
-
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "port": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "connection-id": spice connection id. All channels with the same id
- belong to the same spice session (json-int)
- - "channel-type": channel type. "1" is the main control channel, filter for
- this one if you want track spice sessions only (json-int)
- - "channel-id": channel id. Usually "0", might be different needed when
- multiple channels of the same type exist, such as multiple
- display channels in a multihead setup (json-int)
- - "tls": whevener the channel is encrypted (json-bool)
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
- "event": "SPICE_INITIALIZED",
- "data": {"server": {"auth": "spice", "port": "5921",
- "family": "ipv4", "host": "127.0.0.1"},
- "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
- "connection-id": 1804289383, "host": "127.0.0.1",
- "channel-id": 0, "tls": true}
-}}
-
-STOP
-----
-
-Emitted when the Virtual Machine is stopped.
-
-Data: None.
-
-Example:
-
-{ "event": "STOP",
- "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
-
-SUSPEND
--------
-
-Emitted when guest enters S3 state.
-
-Data: None.
-
-Example:
-
-{ "event": "SUSPEND",
- "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
-
-SUSPEND_DISK
-------------
-
-Emitted when the guest makes a request to enter S4 state.
-
-Data: None.
-
-Example:
-
-{ "event": "SUSPEND_DISK",
- "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
-
-Note: QEMU shuts down when entering S4 state.
-
-VNC_CONNECTED
--------------
-
-Emitted when a VNC client establishes a connection.
-
-Data:
-
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "service": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "service": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "event": "VNC_CONNECTED",
- "data": {
- "server": { "auth": "sasl", "family": "ipv4",
- "service": "5901", "host": "0.0.0.0" },
- "client": { "family": "ipv4", "service": "58425",
- "host": "127.0.0.1" } },
- "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
-
-
-Note: This event is emitted before any authentication takes place, thus
-the authentication ID is not provided.
-
-VNC_DISCONNECTED
-----------------
-
-Emitted when the connection is closed.
-
-Data:
-
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "service": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "service": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "x509_dname": TLS dname (json-string, optional)
- - "sasl_username": SASL username (json-string, optional)
-
-Example:
-
-{ "event": "VNC_DISCONNECTED",
- "data": {
- "server": { "auth": "sasl", "family": "ipv4",
- "service": "5901", "host": "0.0.0.0" },
- "client": { "family": "ipv4", "service": "58425",
- "host": "127.0.0.1", "sasl_username": "luiz" } },
- "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
-
-VNC_INITIALIZED
----------------
-
-Emitted after authentication takes place (if any) and the VNC session is
-made active.
-
-Data:
-
-- "server": Server information (json-object)
- - "host": IP address (json-string)
- - "service": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
- - "host": IP address (json-string)
- - "service": port number (json-string)
- - "family": address family (json-string, "ipv4" or "ipv6")
- - "x509_dname": TLS dname (json-string, optional)
- - "sasl_username": SASL username (json-string, optional)
-
-Example:
-
-{ "event": "VNC_INITIALIZED",
- "data": {
- "server": { "auth": "sasl", "family": "ipv4",
- "service": "5901", "host": "0.0.0.0"},
- "client": { "family": "ipv4", "service": "46089",
- "host": "127.0.0.1", "sasl_username": "luiz" } },
- "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
-
-WAKEUP
-------
-
-Emitted when the guest has woken up from S3 and is running.
-
-Data: None.
-
-Example:
-
-{ "event": "WATCHDOG",
- "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-WATCHDOG
---------
-
-Emitted when the watchdog device's timer is expired.
-
-Data:
-
-- "action": Action that has been taken, it's one of the following (json-string):
- "reset", "shutdown", "poweroff", "pause", "debug", or "none"
-
-Example:
-
-{ "event": "WATCHDOG",
- "data": { "action": "reset" },
- "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
-followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-GUEST_PANICKED
---------------
-
-Emitted when guest OS panic is detected.
-
-Data:
-
-- "action": Action that has been taken (json-string, currently always "pause").
-
-Example:
-
-{ "event": "GUEST_PANICKED",
- "data": { "action": "pause" } }
diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
deleted file mode 100644
index a277896..0000000
--- a/QMP/qmp-spec.txt
+++ /dev/null
@@ -1,282 +0,0 @@
- QEMU Monitor Protocol Specification - Version 0.1
-
-1. Introduction
-===============
-
-This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
-which is available for applications to control QEMU at the machine-level.
-
-To enable QMP support, QEMU has to be run in "control mode". This is done by
-starting QEMU with the appropriate command-line options. Please, refer to the
-QEMU manual page for more information.
-
-2. Protocol Specification
-=========================
-
-This section details the protocol format. For the purpose of this document
-"Client" is any application which is communicating with QEMU in control mode,
-and "Server" is QEMU itself.
-
-JSON data structures, when mentioned in this document, are always in the
-following format:
-
- json-DATA-STRUCTURE-NAME
-
-Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by
-the JSON standard:
-
-http://www.ietf.org/rfc/rfc4627.txt
-
-For convenience, json-object members and json-array elements mentioned in
-this document will be in a certain order. However, in real protocol usage
-they can be in ANY order, thus no particular order should be assumed.
-
-2.1 General Definitions
------------------------
-
-2.1.1 All interactions transmitted by the Server are json-objects, always
- terminating with CRLF
-
-2.1.2 All json-objects members are mandatory when not specified otherwise
-
-2.2 Server Greeting
--------------------
-
-Right when connected the Server will issue a greeting message, which signals
-that the connection has been successfully established and that the Server is
-ready for capabilities negotiation (for more information refer to section
-'4. Capabilities Negotiation').
-
-The format is:
-
-{ "QMP": { "version": json-object, "capabilities": json-array } }
-
- Where,
-
-- The "version" member contains the Server's version information (the format
- is the same of the 'query-version' command)
-- The "capabilities" member specify the availability of features beyond the
- baseline specification
-
-2.3 Issuing Commands
---------------------
-
-The format for command execution is:
-
-{ "execute": json-string, "arguments": json-object, "id": json-value }
-
- Where,
-
-- The "execute" member identifies the command to be executed by the Server
-- The "arguments" member is used to pass any arguments required for the
- execution of the command, it is optional when no arguments are required
-- The "id" member is a transaction identification associated with the
- command execution, it is optional and will be part of the response if
- provided
-
-2.4 Commands Responses
-----------------------
-
-There are two possible responses which the Server will issue as the result
-of a command execution: success or error.
-
-2.4.1 success
--------------
-
-The success response is issued when the command execution has finished
-without errors.
-
-The format is:
-
-{ "return": json-object, "id": json-value }
-
- Where,
-
-- The "return" member contains the command returned data, which is defined
- in a per-command basis or an empty json-object if the command does not
- return data
-- The "id" member contains the transaction identification associated
- with the command execution (if issued by the Client)
-
-2.4.2 error
------------
-
-The error response is issued when the command execution could not be
-completed because of an error condition.
-
-The format is:
-
-{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
-
- Where,
-
-- The "class" member contains the error class name (eg. "GenericError")
-- The "desc" member is a human-readable error message. Clients should
- not attempt to parse this message.
-- The "id" member contains the transaction identification associated with
- the command execution (if issued by the Client)
-
-NOTE: Some errors can occur before the Server is able to read the "id" member,
-in these cases the "id" member will not be part of the error response, even
-if provided by the client.
-
-2.5 Asynchronous events
------------------------
-
-As a result of state changes, the Server may send messages unilaterally
-to the Client at any time. They are called 'asynchronous events'.
-
-The format is:
-
-{ "event": json-string, "data": json-object,
- "timestamp": { "seconds": json-number, "microseconds": json-number } }
-
- Where,
-
-- The "event" member contains the event's name
-- The "data" member contains event specific data, which is defined in a
- per-event basis, it is optional
-- The "timestamp" member contains the exact time of when the event occurred
- in the Server. It is a fixed json-object with time in seconds and
- microseconds
-
-For a listing of supported asynchronous events, please, refer to the
-qmp-events.txt file.
-
-3. QMP Examples
-===============
-
-This section provides some examples of real QMP usage, in all of them
-'C' stands for 'Client' and 'S' stands for 'Server'.
-
-3.1 Server greeting
--------------------
-
-S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
-
-3.2 Simple 'stop' execution
----------------------------
-
-C: { "execute": "stop" }
-S: {"return": {}}
-
-3.3 KVM information
--------------------
-
-C: { "execute": "query-kvm", "id": "example" }
-S: {"return": {"enabled": true, "present": true}, "id": "example"}
-
-3.4 Parsing error
-------------------
-
-C: { "execute": }
-S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
-
-3.5 Powerdown event
--------------------
-
-S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
-"POWERDOWN"}
-
-4. Capabilities Negotiation
-----------------------------
-
-When a Client successfully establishes a connection, the Server is in
-Capabilities Negotiation mode.
-
-In this mode only the 'qmp_capabilities' command is allowed to run, all
-other commands will return the CommandNotFound error. Asynchronous messages
-are not delivered either.
-
-Clients should use the 'qmp_capabilities' command to enable capabilities
-advertised in the Server's greeting (section '2.2 Server Greeting') they
-support.
-
-When the 'qmp_capabilities' command is issued, and if it does not return an
-error, the Server enters in Command mode where capabilities changes take
-effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
-messages are delivered.
-
-5 Compatibility Considerations
-------------------------------
-
-All protocol changes or new features which modify the protocol format in an
-incompatible way are disabled by default and will be advertised by the
-capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
-that array and enable the capabilities they support.
-
-The QMP Server performs a type check on the arguments to a command. It
-generates an error if a value does not have the expected type for its
-key, or if it does not understand a key that the Client included. The
-strictness of the Server catches wrong assumptions of Clients about
-the Server's schema. Clients can assume that, when such validation
-errors occur, they will be reported before the command generated any
-side effect.
-
-However, Clients must not assume any particular:
-
-- Length of json-arrays
-- Size of json-objects; in particular, future versions of QEMU may add
- new keys and Clients should be able to ignore them.
-- Order of json-object members or json-array elements
-- Amount of errors generated by a command, that is, new errors can be added
- to any existing command in newer versions of the Server
-
-Of course, the Server does guarantee to send valid JSON. But apart from
-this, a Client should be "conservative in what they send, and liberal in
-what they accept".
-
-6. Downstream extension of QMP
-------------------------------
-
-We recommend that downstream consumers of QEMU do *not* modify QMP.
-Management tools should be able to support both upstream and downstream
-versions of QMP without special logic, and downstream extensions are
-inherently at odds with that.
-
-However, we recognize that it is sometimes impossible for downstreams to
-avoid modifying QMP. Both upstream and downstream need to take care to
-preserve long-term compatibility and interoperability.
-
-To help with that, QMP reserves JSON object member names beginning with
-'__' (double underscore) for downstream use ("downstream names"). This
-means upstream will never use any downstream names for its commands,
-arguments, errors, asynchronous events, and so forth.
-
-Any new names downstream wishes to add must begin with '__'. To
-ensure compatibility with other downstreams, it is strongly
-recommended that you prefix your downstram names with '__RFQDN_' where
-RFQDN is a valid, reverse fully qualified domain name which you
-control. For example, a qemu-kvm specific monitor command would be:
-
- (qemu) __org.linux-kvm_enable_irqchip
-
-Downstream must not change the server greeting (section 2.2) other than
-to offer additional capabilities. But see below for why even that is
-discouraged.
-
-Section '5 Compatibility Considerations' applies to downstream as well
-as to upstream, obviously. It follows that downstream must behave
-exactly like upstream for any input not containing members with
-downstream names ("downstream members"), except it may add members
-with downstream names to its output.
-
-Thus, a client should not be able to distinguish downstream from
-upstream as long as it doesn't send input with downstream members, and
-properly ignores any downstream members in the output it receives.
-
-Advice on downstream modifications:
-
-1. Introducing new commands is okay. If you want to extend an existing
- command, consider introducing a new one with the new behaviour
- instead.
-
-2. Introducing new asynchronous messages is okay. If you want to extend
- an existing message, consider adding a new one instead.
-
-3. Introducing new errors for use in new commands is okay. Adding new
- errors to existing commands counts as extension, so 1. applies.
-
-4. New capabilities are strongly discouraged. Capabilities are for
- evolving the basic protocol, and multiple diverging basic protocol
- dialects are most undesirable.
diff --git a/docs/qmp/README b/docs/qmp/README
new file mode 100644
index 0000000..c95a08c
--- /dev/null
+++ b/docs/qmp/README
@@ -0,0 +1,88 @@
+ QEMU Monitor Protocol
+ =====================
+
+Introduction
+-------------
+
+The QEMU Monitor Protocol (QMP) allows applications to communicate with
+QEMU's Monitor.
+
+QMP is JSON[1] based and currently has the following features:
+
+- Lightweight, text-based, easy to parse data format
+- Asynchronous messages support (ie. events)
+- Capabilities Negotiation
+
+For detailed information on QMP's usage, please, refer to the following files:
+
+o qmp-spec.txt QEMU Monitor Protocol current specification
+o qmp-commands.txt QMP supported commands (auto-generated at build-time)
+o qmp-events.txt List of available asynchronous events
+
+There is also a simple Python script called 'qmp-shell' available.
+
+IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
+section in the qmp-commands.txt file before making any serious use of QMP.
+
+
+[1] http://www.json.org
+
+Usage
+-----
+
+To enable QMP, you need a QEMU monitor instance in "control mode". There are
+two ways of doing this.
+
+The simplest one is using the '-qmp' command-line option. The following
+example makes QMP available on localhost port 4444:
+
+ $ qemu [...] -qmp tcp:localhost:4444,server
+
+However, in order to have more complex combinations, like multiple monitors,
+the '-mon' command-line option should be used along with the '-chardev' one.
+For instance, the following example creates one user monitor on stdio and one
+QMP monitor on localhost port 4444.
+
+ $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
+ -chardev socket,id=mon1,host=localhost,port=4444,server \
+ -mon chardev=mon1,mode=control
+
+Please, refer to QEMU's manpage for more information.
+
+Simple Testing
+--------------
+
+To manually test QMP one can connect with telnet and issue commands by hand:
+
+$ telnet localhost 4444
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
+{ "execute": "qmp_capabilities" }
+{"return": {}}
+{ "execute": "query-version" }
+{"return": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}}
+
+Development Process
+-------------------
+
+When changing QMP's interface (by adding new commands, events or modifying
+existing ones) it's mandatory to update the relevant documentation, which is
+one (or more) of the files listed in the 'Introduction' section*.
+
+Also, it's strongly recommended to send the documentation patch first, before
+doing any code change. This is so because:
+
+ 1. Avoids the code dictating the interface
+
+ 2. Review can improve your interface. Letting that happen before
+ you implement it can save you work.
+
+* The qmp-commands.txt file is generated from the qmp-commands.hx one, which
+ is the file that should be edited.
+
+Homepage
+--------
+
+http://wiki.qemu.org/QMP
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
new file mode 100644
index 0000000..39b6016
--- /dev/null
+++ b/docs/qmp/qmp-events.txt
@@ -0,0 +1,480 @@
+ QEMU Monitor Protocol Events
+ ============================
+
+BALLOON_CHANGE
+--------------
+
+Emitted when the guest changes the actual BALLOON level. This
+value is equivalent to the 'actual' field return by the
+'query-balloon' command
+
+Data:
+
+- "actual": actual level of the guest memory balloon in bytes (json-number)
+
+Example:
+
+{ "event": "BALLOON_CHANGE",
+ "data": { "actual": 944766976 },
+ "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+
+BLOCK_IO_ERROR
+--------------
+
+Emitted when a disk I/O error occurs.
+
+Data:
+
+- "device": device name (json-string)
+- "operation": I/O operation (json-string, "read" or "write")
+- "action": action that has been taken, it's one of the following (json-string):
+ "ignore": error has been ignored
+ "report": error has been reported to the device
+ "stop": error caused VM to be stopped
+
+Example:
+
+{ "event": "BLOCK_IO_ERROR",
+ "data": { "device": "ide0-hd1",
+ "operation": "write",
+ "action": "stop" },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+Note: If action is "stop", a STOP event will eventually follow the
+BLOCK_IO_ERROR event.
+
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type": Job type (json-string; "stream" for image streaming
+ "commit" for block commit)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 134217728,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+BLOCK_JOB_COMPLETED
+-------------------
+
+Emitted when a block job has completed.
+
+Data:
+
+- "type": Job type (json-string; "stream" for image streaming
+ "commit" for block commit)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that streaming
+ has failed and clients should not try to interpret the error
+ string.
+
+Example:
+
+{ "event": "BLOCK_JOB_COMPLETED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 10737418240,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+BLOCK_JOB_ERROR
+---------------
+
+Emitted when a block job encounters an error.
+
+Data:
+
+- "device": device name (json-string)
+- "operation": I/O operation (json-string, "read" or "write")
+- "action": action that has been taken, it's one of the following (json-string):
+ "ignore": error has been ignored, the job may fail later
+ "report": error will be reported and the job canceled
+ "stop": error caused job to be paused
+
+Example:
+
+{ "event": "BLOCK_JOB_ERROR",
+ "data": { "device": "ide0-hd1",
+ "operation": "write",
+ "action": "stop" },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+BLOCK_JOB_READY
+---------------
+
+Emitted when a block job is ready to complete.
+
+Data:
+
+- "device": device name (json-string)
+
+Example:
+
+{ "event": "BLOCK_JOB_READY",
+ "data": { "device": "ide0-hd1" },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
+event.
+
+DEVICE_DELETED
+-----------------
+
+Emitted whenever the device removal completion is acknowledged
+by the guest.
+At this point, it's safe to reuse the specified device ID.
+Device removal can be initiated by the guest or by HMP/QMP commands.
+
+Data:
+
+- "device": device name (json-string, optional)
+- "path": device path (json-string)
+
+{ "event": "DEVICE_DELETED",
+ "data": { "device": "virtio-net-pci-0",
+ "path": "/machine/peripheral/virtio-net-pci-0" },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+DEVICE_TRAY_MOVED
+-----------------
+
+It's emitted whenever the tray of a removable device is moved by the guest
+or by HMP/QMP commands.
+
+Data:
+
+- "device": device name (json-string)
+- "tray-open": true if the tray has been opened or false if it has been closed
+ (json-bool)
+
+{ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+ "tray-open": true
+ },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+NIC_RX_FILTER_CHANGED
+-----------------
+
+The event is emitted once until the query command is executed,
+the first event will always be emitted.
+
+Data:
+
+- "name": net client name (json-string)
+- "path": device path (json-string)
+
+{ "event": "NIC_RX_FILTER_CHANGED",
+ "data": { "name": "vnet0",
+ "path": "/machine/peripheral/vnet0/virtio-backend" },
+ "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
+}
+
+RESET
+-----
+
+Emitted when the Virtual Machine is reseted.
+
+Data: None.
+
+Example:
+
+{ "event": "RESET",
+ "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
+
+RESUME
+------
+
+Emitted when the Virtual Machine resumes execution.
+
+Data: None.
+
+Example:
+
+{ "event": "RESUME",
+ "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
+
+RTC_CHANGE
+----------
+
+Emitted when the guest changes the RTC time.
+
+Data:
+
+- "offset": Offset between base RTC clock (as specified by -rtc base), and
+new RTC clock value (json-number)
+
+Example:
+
+{ "event": "RTC_CHANGE",
+ "data": { "offset": 78 },
+ "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+
+SHUTDOWN
+--------
+
+Emitted when the Virtual Machine is powered down.
+
+Data: None.
+
+Example:
+
+{ "event": "SHUTDOWN",
+ "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+
+Note: If the command-line option "-no-shutdown" has been specified, a STOP
+event will eventually follow the SHUTDOWN event.
+
+SPICE_CONNECTED, SPICE_DISCONNECTED
+-----------------------------------
+
+Emitted when a SPICE client connects or disconnects.
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+ "event": "SPICE_CONNECTED",
+ "data": {
+ "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+ "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+}}
+
+SPICE_INITIALIZED
+-----------------
+
+Emitted after initial handshake and authentication takes place (if any)
+and the SPICE channel is up'n'running
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "connection-id": spice connection id. All channels with the same id
+ belong to the same spice session (json-int)
+ - "channel-type": channel type. "1" is the main control channel, filter for
+ this one if you want track spice sessions only (json-int)
+ - "channel-id": channel id. Usually "0", might be different needed when
+ multiple channels of the same type exist, such as multiple
+ display channels in a multihead setup (json-int)
+ - "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+ "event": "SPICE_INITIALIZED",
+ "data": {"server": {"auth": "spice", "port": "5921",
+ "family": "ipv4", "host": "127.0.0.1"},
+ "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+ "connection-id": 1804289383, "host": "127.0.0.1",
+ "channel-id": 0, "tls": true}
+}}
+
+STOP
+----
+
+Emitted when the Virtual Machine is stopped.
+
+Data: None.
+
+Example:
+
+{ "event": "STOP",
+ "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
+
+SUSPEND
+-------
+
+Emitted when guest enters S3 state.
+
+Data: None.
+
+Example:
+
+{ "event": "SUSPEND",
+ "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+
+SUSPEND_DISK
+------------
+
+Emitted when the guest makes a request to enter S4 state.
+
+Data: None.
+
+Example:
+
+{ "event": "SUSPEND_DISK",
+ "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+
+Note: QEMU shuts down when entering S4 state.
+
+VNC_CONNECTED
+-------------
+
+Emitted when a VNC client establishes a connection.
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "service": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "service": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "event": "VNC_CONNECTED",
+ "data": {
+ "server": { "auth": "sasl", "family": "ipv4",
+ "service": "5901", "host": "0.0.0.0" },
+ "client": { "family": "ipv4", "service": "58425",
+ "host": "127.0.0.1" } },
+ "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+
+
+Note: This event is emitted before any authentication takes place, thus
+the authentication ID is not provided.
+
+VNC_DISCONNECTED
+----------------
+
+Emitted when the connection is closed.
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "service": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "service": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "x509_dname": TLS dname (json-string, optional)
+ - "sasl_username": SASL username (json-string, optional)
+
+Example:
+
+{ "event": "VNC_DISCONNECTED",
+ "data": {
+ "server": { "auth": "sasl", "family": "ipv4",
+ "service": "5901", "host": "0.0.0.0" },
+ "client": { "family": "ipv4", "service": "58425",
+ "host": "127.0.0.1", "sasl_username": "luiz" } },
+ "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+
+VNC_INITIALIZED
+---------------
+
+Emitted after authentication takes place (if any) and the VNC session is
+made active.
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "service": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "service": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+ - "x509_dname": TLS dname (json-string, optional)
+ - "sasl_username": SASL username (json-string, optional)
+
+Example:
+
+{ "event": "VNC_INITIALIZED",
+ "data": {
+ "server": { "auth": "sasl", "family": "ipv4",
+ "service": "5901", "host": "0.0.0.0"},
+ "client": { "family": "ipv4", "service": "46089",
+ "host": "127.0.0.1", "sasl_username": "luiz" } },
+ "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
+
+WAKEUP
+------
+
+Emitted when the guest has woken up from S3 and is running.
+
+Data: None.
+
+Example:
+
+{ "event": "WATCHDOG",
+ "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+
+WATCHDOG
+--------
+
+Emitted when the watchdog device's timer is expired.
+
+Data:
+
+- "action": Action that has been taken, it's one of the following (json-string):
+ "reset", "shutdown", "poweroff", "pause", "debug", or "none"
+
+Example:
+
+{ "event": "WATCHDOG",
+ "data": { "action": "reset" },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
+followed respectively by the RESET, SHUTDOWN, or STOP events.
+
+GUEST_PANICKED
+--------------
+
+Emitted when guest OS panic is detected.
+
+Data:
+
+- "action": Action that has been taken (json-string, currently always "pause").
+
+Example:
+
+{ "event": "GUEST_PANICKED",
+ "data": { "action": "pause" } }
diff --git a/docs/qmp/qmp-spec.txt b/docs/qmp/qmp-spec.txt
new file mode 100644
index 0000000..a277896
--- /dev/null
+++ b/docs/qmp/qmp-spec.txt
@@ -0,0 +1,282 @@
+ QEMU Monitor Protocol Specification - Version 0.1
+
+1. Introduction
+===============
+
+This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
+which is available for applications to control QEMU at the machine-level.
+
+To enable QMP support, QEMU has to be run in "control mode". This is done by
+starting QEMU with the appropriate command-line options. Please, refer to the
+QEMU manual page for more information.
+
+2. Protocol Specification
+=========================
+
+This section details the protocol format. For the purpose of this document
+"Client" is any application which is communicating with QEMU in control mode,
+and "Server" is QEMU itself.
+
+JSON data structures, when mentioned in this document, are always in the
+following format:
+
+ json-DATA-STRUCTURE-NAME
+
+Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by
+the JSON standard:
+
+http://www.ietf.org/rfc/rfc4627.txt
+
+For convenience, json-object members and json-array elements mentioned in
+this document will be in a certain order. However, in real protocol usage
+they can be in ANY order, thus no particular order should be assumed.
+
+2.1 General Definitions
+-----------------------
+
+2.1.1 All interactions transmitted by the Server are json-objects, always
+ terminating with CRLF
+
+2.1.2 All json-objects members are mandatory when not specified otherwise
+
+2.2 Server Greeting
+-------------------
+
+Right when connected the Server will issue a greeting message, which signals
+that the connection has been successfully established and that the Server is
+ready for capabilities negotiation (for more information refer to section
+'4. Capabilities Negotiation').
+
+The format is:
+
+{ "QMP": { "version": json-object, "capabilities": json-array } }
+
+ Where,
+
+- The "version" member contains the Server's version information (the format
+ is the same of the 'query-version' command)
+- The "capabilities" member specify the availability of features beyond the
+ baseline specification
+
+2.3 Issuing Commands
+--------------------
+
+The format for command execution is:
+
+{ "execute": json-string, "arguments": json-object, "id": json-value }
+
+ Where,
+
+- The "execute" member identifies the command to be executed by the Server
+- The "arguments" member is used to pass any arguments required for the
+ execution of the command, it is optional when no arguments are required
+- The "id" member is a transaction identification associated with the
+ command execution, it is optional and will be part of the response if
+ provided
+
+2.4 Commands Responses
+----------------------
+
+There are two possible responses which the Server will issue as the result
+of a command execution: success or error.
+
+2.4.1 success
+-------------
+
+The success response is issued when the command execution has finished
+without errors.
+
+The format is:
+
+{ "return": json-object, "id": json-value }
+
+ Where,
+
+- The "return" member contains the command returned data, which is defined
+ in a per-command basis or an empty json-object if the command does not
+ return data
+- The "id" member contains the transaction identification associated
+ with the command execution (if issued by the Client)
+
+2.4.2 error
+-----------
+
+The error response is issued when the command execution could not be
+completed because of an error condition.
+
+The format is:
+
+{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
+
+ Where,
+
+- The "class" member contains the error class name (eg. "GenericError")
+- The "desc" member is a human-readable error message. Clients should
+ not attempt to parse this message.
+- The "id" member contains the transaction identification associated with
+ the command execution (if issued by the Client)
+
+NOTE: Some errors can occur before the Server is able to read the "id" member,
+in these cases the "id" member will not be part of the error response, even
+if provided by the client.
+
+2.5 Asynchronous events
+-----------------------
+
+As a result of state changes, the Server may send messages unilaterally
+to the Client at any time. They are called 'asynchronous events'.
+
+The format is:
+
+{ "event": json-string, "data": json-object,
+ "timestamp": { "seconds": json-number, "microseconds": json-number } }
+
+ Where,
+
+- The "event" member contains the event's name
+- The "data" member contains event specific data, which is defined in a
+ per-event basis, it is optional
+- The "timestamp" member contains the exact time of when the event occurred
+ in the Server. It is a fixed json-object with time in seconds and
+ microseconds
+
+For a listing of supported asynchronous events, please, refer to the
+qmp-events.txt file.
+
+3. QMP Examples
+===============
+
+This section provides some examples of real QMP usage, in all of them
+'C' stands for 'Client' and 'S' stands for 'Server'.
+
+3.1 Server greeting
+-------------------
+
+S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
+
+3.2 Simple 'stop' execution
+---------------------------
+
+C: { "execute": "stop" }
+S: {"return": {}}
+
+3.3 KVM information
+-------------------
+
+C: { "execute": "query-kvm", "id": "example" }
+S: {"return": {"enabled": true, "present": true}, "id": "example"}
+
+3.4 Parsing error
+------------------
+
+C: { "execute": }
+S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
+
+3.5 Powerdown event
+-------------------
+
+S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
+"POWERDOWN"}
+
+4. Capabilities Negotiation
+----------------------------
+
+When a Client successfully establishes a connection, the Server is in
+Capabilities Negotiation mode.
+
+In this mode only the 'qmp_capabilities' command is allowed to run, all
+other commands will return the CommandNotFound error. Asynchronous messages
+are not delivered either.
+
+Clients should use the 'qmp_capabilities' command to enable capabilities
+advertised in the Server's greeting (section '2.2 Server Greeting') they
+support.
+
+When the 'qmp_capabilities' command is issued, and if it does not return an
+error, the Server enters in Command mode where capabilities changes take
+effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
+messages are delivered.
+
+5 Compatibility Considerations
+------------------------------
+
+All protocol changes or new features which modify the protocol format in an
+incompatible way are disabled by default and will be advertised by the
+capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
+that array and enable the capabilities they support.
+
+The QMP Server performs a type check on the arguments to a command. It
+generates an error if a value does not have the expected type for its
+key, or if it does not understand a key that the Client included. The
+strictness of the Server catches wrong assumptions of Clients about
+the Server's schema. Clients can assume that, when such validation
+errors occur, they will be reported before the command generated any
+side effect.
+
+However, Clients must not assume any particular:
+
+- Length of json-arrays
+- Size of json-objects; in particular, future versions of QEMU may add
+ new keys and Clients should be able to ignore them.
+- Order of json-object members or json-array elements
+- Amount of errors generated by a command, that is, new errors can be added
+ to any existing command in newer versions of the Server
+
+Of course, the Server does guarantee to send valid JSON. But apart from
+this, a Client should be "conservative in what they send, and liberal in
+what they accept".
+
+6. Downstream extension of QMP
+------------------------------
+
+We recommend that downstream consumers of QEMU do *not* modify QMP.
+Management tools should be able to support both upstream and downstream
+versions of QMP without special logic, and downstream extensions are
+inherently at odds with that.
+
+However, we recognize that it is sometimes impossible for downstreams to
+avoid modifying QMP. Both upstream and downstream need to take care to
+preserve long-term compatibility and interoperability.
+
+To help with that, QMP reserves JSON object member names beginning with
+'__' (double underscore) for downstream use ("downstream names"). This
+means upstream will never use any downstream names for its commands,
+arguments, errors, asynchronous events, and so forth.
+
+Any new names downstream wishes to add must begin with '__'. To
+ensure compatibility with other downstreams, it is strongly
+recommended that you prefix your downstram names with '__RFQDN_' where
+RFQDN is a valid, reverse fully qualified domain name which you
+control. For example, a qemu-kvm specific monitor command would be:
+
+ (qemu) __org.linux-kvm_enable_irqchip
+
+Downstream must not change the server greeting (section 2.2) other than
+to offer additional capabilities. But see below for why even that is
+discouraged.
+
+Section '5 Compatibility Considerations' applies to downstream as well
+as to upstream, obviously. It follows that downstream must behave
+exactly like upstream for any input not containing members with
+downstream names ("downstream members"), except it may add members
+with downstream names to its output.
+
+Thus, a client should not be able to distinguish downstream from
+upstream as long as it doesn't send input with downstream members, and
+properly ignores any downstream members in the output it receives.
+
+Advice on downstream modifications:
+
+1. Introducing new commands is okay. If you want to extend an existing
+ command, consider introducing a new one with the new behaviour
+ instead.
+
+2. Introducing new asynchronous messages is okay. If you want to extend
+ an existing message, consider adding a new one instead.
+
+3. Introducing new errors for use in new commands is okay. Adding new
+ errors to existing commands counts as extension, so 1. applies.
+
+4. New capabilities are strongly discouraged. Capabilities are for
+ evolving the basic protocol, and multiple diverging basic protocol
+ dialects are most undesirable.
--
1.8.1.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 3/6] QMP: QMP/ -> docs/qmp/
2013-09-11 20:52 ` [Qemu-devel] [PATCH 3/6] QMP: QMP/ -> docs/qmp/ Luiz Capitulino
@ 2013-09-11 22:15 ` Eric Blake
0 siblings, 0 replies; 20+ messages in thread
From: Eric Blake @ 2013-09-11 22:15 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel, armbru
[-- Attachment #1: Type: text/plain, Size: 2087 bytes --]
On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
> QMP/README | 88 ---------
> QMP/qmp-events.txt | 480 ------------------------------------------------
> QMP/qmp-spec.txt | 282 ----------------------------
> docs/qmp/README | 88 +++++++++
> docs/qmp/qmp-events.txt | 480 ++++++++++++++++++++++++++++++++++++++++++++++++
> docs/qmp/qmp-spec.txt | 282 ++++++++++++++++++++++++++++
> 6 files changed, 850 insertions(+), 850 deletions(-)
> delete mode 100644 QMP/README
> delete mode 100644 QMP/qmp-events.txt
> delete mode 100644 QMP/qmp-spec.txt
> create mode 100644 docs/qmp/README
> create mode 100644 docs/qmp/qmp-events.txt
> create mode 100644 docs/qmp/qmp-spec.txt
Repeat after me:
git config diff.renames true
Only after doing that, am I able to make a QUICK review that it was pure
motion.
Reviewed-by: Eric Blake <eblake@redhat.com>
From dcb53697c92d5f22130102978a970fe805416725 Mon Sep 17 00:00:00 2001
From: Luiz Capitulino <lcapitulino@redhat.com>
Date: Wed, 11 Sep 2013 16:52:14 -0400
Subject: [PATCH] QMP: QMP/ -> docs/qmp/
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
{QMP => docs/qmp}/README | 0
{QMP => docs/qmp}/qmp-events.txt | 0
{QMP => docs/qmp}/qmp-spec.txt | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename {QMP => docs/qmp}/README (100%)
rename {QMP => docs/qmp}/qmp-events.txt (100%)
rename {QMP => docs/qmp}/qmp-spec.txt (100%)
diff --git a/QMP/README b/docs/qmp/README
similarity index 100%
rename from QMP/README
rename to docs/qmp/README
diff --git a/QMP/qmp-events.txt b/docs/qmp/qmp-events.txt
similarity index 100%
rename from QMP/qmp-events.txt
rename to docs/qmp/qmp-events.txt
diff --git a/QMP/qmp-spec.txt b/docs/qmp/qmp-spec.txt
similarity index 100%
rename from QMP/qmp-spec.txt
rename to docs/qmp/qmp-spec.txt
--
1.8.3.1
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 4/6] QMP: Update README file
2013-09-11 20:52 [Qemu-devel] [PATCH 0/6] QMP: re-organize documentation Luiz Capitulino
` (2 preceding siblings ...)
2013-09-11 20:52 ` [Qemu-devel] [PATCH 3/6] QMP: QMP/ -> docs/qmp/ Luiz Capitulino
@ 2013-09-11 20:52 ` Luiz Capitulino
2013-09-11 23:13 ` Eric Blake
2013-09-11 20:52 ` [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt Luiz Capitulino
2013-09-11 20:52 ` [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes Luiz Capitulino
5 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-11 20:52 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru
Drop unneeded info, fix some of the examples and rename QEMU Monitor
Protocol to QEMU Machine Protocol.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
docs/qmp/README | 99 ++++++++++++++++++++++++++++-----------------------------
1 file changed, 49 insertions(+), 50 deletions(-)
diff --git a/docs/qmp/README b/docs/qmp/README
index c95a08c..85c4bc1 100644
--- a/docs/qmp/README
+++ b/docs/qmp/README
@@ -1,13 +1,13 @@
- QEMU Monitor Protocol
+ QEMU Machine Protocol
=====================
Introduction
--------------
+------------
-The QEMU Monitor Protocol (QMP) allows applications to communicate with
-QEMU's Monitor.
+The QEMU Machine Protocol (QMP) allows applications to operate a
+QEMU instance.
-QMP is JSON[1] based and currently has the following features:
+QMP is JSON[1] based and features the following:
- Lightweight, text-based, easy to parse data format
- Asynchronous messages support (ie. events)
@@ -15,37 +15,28 @@ QMP is JSON[1] based and currently has the following features:
For detailed information on QMP's usage, please, refer to the following files:
-o qmp-spec.txt QEMU Monitor Protocol current specification
+o qmp-spec.txt QEMU Machine Protocol current specification
o qmp-commands.txt QMP supported commands (auto-generated at build-time)
o qmp-events.txt List of available asynchronous events
-There is also a simple Python script called 'qmp-shell' available.
-
-IMPORTANT: It's strongly recommended to read the 'Stability Considerations'
-section in the qmp-commands.txt file before making any serious use of QMP.
-
-
[1] http://www.json.org
Usage
-----
-To enable QMP, you need a QEMU monitor instance in "control mode". There are
-two ways of doing this.
+You can use the -qmp option to enable QMP. For example, the following
+makes QMP available on localhost port 4444:
-The simplest one is using the '-qmp' command-line option. The following
-example makes QMP available on localhost port 4444:
+$ qemu [...] -qmp tcp:localhost:4444,server,nowait
- $ qemu [...] -qmp tcp:localhost:4444,server
+However, for more flexibility and to make use of more options, the -mon
+command-line option should be used. For instance, the following example
+creates one HMP instance (human monitor) on stdio and one QMP instance
+on localhost port 4444:
-However, in order to have more complex combinations, like multiple monitors,
-the '-mon' command-line option should be used along with the '-chardev' one.
-For instance, the following example creates one user monitor on stdio and one
-QMP monitor on localhost port 4444.
-
- $ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
- -chardev socket,id=mon1,host=localhost,port=4444,server \
- -mon chardev=mon1,mode=control
+$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
+ -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
+ -mon chardev=mon1,mode=control,pretty=on
Please, refer to QEMU's manpage for more information.
@@ -58,31 +49,39 @@ $ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
-{"QMP": {"version": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}, "capabilities": []}}
-{ "execute": "qmp_capabilities" }
-{"return": {}}
-{ "execute": "query-version" }
-{"return": {"qemu": {"micro": 50, "minor": 13, "major": 0}, "package": ""}}
-
-Development Process
--------------------
+{
+ "QMP": {
+ "version": {
+ "qemu": {
+ "micro": 50,
+ "minor": 6,
+ "major": 1
+ },
+ "package": ""
+ },
+ "capabilities": [
+ ]
+ }
+}
-When changing QMP's interface (by adding new commands, events or modifying
-existing ones) it's mandatory to update the relevant documentation, which is
-one (or more) of the files listed in the 'Introduction' section*.
-
-Also, it's strongly recommended to send the documentation patch first, before
-doing any code change. This is so because:
-
- 1. Avoids the code dictating the interface
-
- 2. Review can improve your interface. Letting that happen before
- you implement it can save you work.
-
-* The qmp-commands.txt file is generated from the qmp-commands.hx one, which
- is the file that should be edited.
-
-Homepage
---------
+{ "execute": "qmp_capabilities" }
+{
+ "return": {
+ }
+}
+
+{ "execute": "query-status" }
+{
+ "return": {
+ "status": "prelaunch",
+ "singlestep": false,
+ "running": false
+ }
+}
+
+Please, refer to the qapi-schema.json file for a complete command reference.
+
+QMP wiki page
+-------------
http://wiki.qemu.org/QMP
--
1.8.1.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt
2013-09-11 20:52 [Qemu-devel] [PATCH 0/6] QMP: re-organize documentation Luiz Capitulino
` (3 preceding siblings ...)
2013-09-11 20:52 ` [Qemu-devel] [PATCH 4/6] QMP: Update README file Luiz Capitulino
@ 2013-09-11 20:52 ` Luiz Capitulino
2013-09-11 23:27 ` Eric Blake
2013-09-11 20:52 ` [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes Luiz Capitulino
5 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-11 20:52 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru
Simplify the text, fix some of the examples.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
docs/qmp/qmp-spec.txt | 65 ++++++++++++++++++++++-----------------------------
1 file changed, 28 insertions(+), 37 deletions(-)
diff --git a/docs/qmp/qmp-spec.txt b/docs/qmp/qmp-spec.txt
index a277896..22568c6 100644
--- a/docs/qmp/qmp-spec.txt
+++ b/docs/qmp/qmp-spec.txt
@@ -1,21 +1,17 @@
- QEMU Monitor Protocol Specification - Version 0.1
+ QEMU Machine Protocol Specification
1. Introduction
===============
-This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
-which is available for applications to control QEMU at the machine-level.
-
-To enable QMP support, QEMU has to be run in "control mode". This is done by
-starting QEMU with the appropriate command-line options. Please, refer to the
-QEMU manual page for more information.
+This document specifies the QEMU Machine Protocol (QMP), a JSON-based protocol
+which is available for applications to operate QEMU at the machine-level.
2. Protocol Specification
=========================
This section details the protocol format. For the purpose of this document
-"Client" is any application which is communicating with QEMU in control mode,
-and "Server" is QEMU itself.
+"Client" is any application which is using QMP to communicate with QEMU and
+"Server" is QEMU itself.
JSON data structures, when mentioned in this document, are always in the
following format:
@@ -47,14 +43,14 @@ that the connection has been successfully established and that the Server is
ready for capabilities negotiation (for more information refer to section
'4. Capabilities Negotiation').
-The format is:
+The greeting message format is:
{ "QMP": { "version": json-object, "capabilities": json-array } }
Where,
- The "version" member contains the Server's version information (the format
- is the same of the 'query-version' command)
+ is the same of the query-version command)
- The "capabilities" member specify the availability of features beyond the
baseline specification
@@ -83,10 +79,7 @@ of a command execution: success or error.
2.4.1 success
-------------
-The success response is issued when the command execution has finished
-without errors.
-
-The format is:
+The format of a success response is:
{ "return": json-object, "id": json-value }
@@ -96,15 +89,12 @@ The format is:
in a per-command basis or an empty json-object if the command does not
return data
- The "id" member contains the transaction identification associated
- with the command execution (if issued by the Client)
+ with the command execution if issued by the Client
2.4.2 error
-----------
-The error response is issued when the command execution could not be
-completed because of an error condition.
-
-The format is:
+The format of an error response is:
{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
@@ -114,7 +104,7 @@ The format is:
- The "desc" member is a human-readable error message. Clients should
not attempt to parse this message.
- The "id" member contains the transaction identification associated with
- the command execution (if issued by the Client)
+ the command execution if issued by the Client
NOTE: Some errors can occur before the Server is able to read the "id" member,
in these cases the "id" member will not be part of the error response, even
@@ -124,9 +114,9 @@ if provided by the client.
-----------------------
As a result of state changes, the Server may send messages unilaterally
-to the Client at any time. They are called 'asynchronous events'.
+to the Client at any time. They are called "asynchronous events".
-The format is:
+The format of asynchronous events is:
{ "event": json-string, "data": json-object,
"timestamp": { "seconds": json-number, "microseconds": json-number } }
@@ -147,36 +137,37 @@ qmp-events.txt file.
===============
This section provides some examples of real QMP usage, in all of them
-'C' stands for 'Client' and 'S' stands for 'Server'.
+"C" stands for "Client" and "S" stands for "Server".
3.1 Server greeting
-------------------
-S: {"QMP": {"version": {"qemu": "0.12.50", "package": ""}, "capabilities": []}}
+S: { "QMP": { "version": { "qemu": { "micro": 50, "minor": 6, "major": 1 },
+ "package": ""}, "capabilities": []}}
3.2 Simple 'stop' execution
---------------------------
C: { "execute": "stop" }
-S: {"return": {}}
+S: { "return": {} }
3.3 KVM information
-------------------
C: { "execute": "query-kvm", "id": "example" }
-S: {"return": {"enabled": true, "present": true}, "id": "example"}
+S: { "return": { "enabled": true, "present": true }, "id": "example"}
3.4 Parsing error
------------------
C: { "execute": }
-S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
+S: { "error": { "class": "GenericError", "desc": "Invalid JSON syntax" } }
3.5 Powerdown event
-------------------
-S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
-"POWERDOWN"}
+S: { "timestamp": { "seconds": 1258551470, "microseconds": 802384 },
+ "event": "POWERDOWN" }
4. Capabilities Negotiation
----------------------------
@@ -184,17 +175,17 @@ S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
When a Client successfully establishes a connection, the Server is in
Capabilities Negotiation mode.
-In this mode only the 'qmp_capabilities' command is allowed to run, all
-other commands will return the CommandNotFound error. Asynchronous messages
-are not delivered either.
+In this mode only the qmp_capabilities command is allowed to run, all
+other commands will return the CommandNotFound error. Asynchronous
+messages are not delivered either.
-Clients should use the 'qmp_capabilities' command to enable capabilities
+Clients should use the qmp_capabilities command to enable capabilities
advertised in the Server's greeting (section '2.2 Server Greeting') they
support.
-When the 'qmp_capabilities' command is issued, and if it does not return an
+When the qmp_capabilities command is issued, and if it does not return an
error, the Server enters in Command mode where capabilities changes take
-effect, all commands (except 'qmp_capabilities') are allowed and asynchronous
+effect, all commands (except qmp_capabilities) are allowed and asynchronous
messages are delivered.
5 Compatibility Considerations
@@ -245,7 +236,7 @@ arguments, errors, asynchronous events, and so forth.
Any new names downstream wishes to add must begin with '__'. To
ensure compatibility with other downstreams, it is strongly
-recommended that you prefix your downstram names with '__RFQDN_' where
+recommended that you prefix your downstream names with '__RFQDN_' where
RFQDN is a valid, reverse fully qualified domain name which you
control. For example, a qemu-kvm specific monitor command would be:
--
1.8.1.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt
2013-09-11 20:52 ` [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt Luiz Capitulino
@ 2013-09-11 23:27 ` Eric Blake
2013-09-13 17:54 ` Luiz Capitulino
0 siblings, 1 reply; 20+ messages in thread
From: Eric Blake @ 2013-09-11 23:27 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel, armbru
[-- Attachment #1: Type: text/plain, Size: 880 bytes --]
On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> Simplify the text, fix some of the examples.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
> docs/qmp/qmp-spec.txt | 65 ++++++++++++++++++++++-----------------------------
> 1 file changed, 28 insertions(+), 37 deletions(-)
>
> diff --git a/docs/qmp/qmp-spec.txt b/docs/qmp/qmp-spec.txt
> index a277896..22568c6 100644
> --- a/docs/qmp/qmp-spec.txt
> +++ b/docs/qmp/qmp-spec.txt
> @@ -1,21 +1,17 @@
> - QEMU Monitor Protocol Specification - Version 0.1
> + QEMU Machine Protocol Specification
Do we want a protocol version number? I guess if we ever add
capabilities, we can worry about it then.
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt
2013-09-11 23:27 ` Eric Blake
@ 2013-09-13 17:54 ` Luiz Capitulino
2013-09-13 18:00 ` Eric Blake
0 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-13 17:54 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, armbru
On Wed, 11 Sep 2013 17:27:58 -0600
Eric Blake <eblake@redhat.com> wrote:
> On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> > Simplify the text, fix some of the examples.
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> > docs/qmp/qmp-spec.txt | 65 ++++++++++++++++++++++-----------------------------
> > 1 file changed, 28 insertions(+), 37 deletions(-)
>
> >
> > diff --git a/docs/qmp/qmp-spec.txt b/docs/qmp/qmp-spec.txt
> > index a277896..22568c6 100644
> > --- a/docs/qmp/qmp-spec.txt
> > +++ b/docs/qmp/qmp-spec.txt
> > @@ -1,21 +1,17 @@
> > - QEMU Monitor Protocol Specification - Version 0.1
> > + QEMU Machine Protocol Specification
>
> Do we want a protocol version number? I guess if we ever add
> capabilities, we can worry about it then.
Yes, but I don't think we want it. This is the sole place where
a version number appears and it's quite meaningless.
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt
2013-09-13 17:54 ` Luiz Capitulino
@ 2013-09-13 18:00 ` Eric Blake
0 siblings, 0 replies; 20+ messages in thread
From: Eric Blake @ 2013-09-13 18:00 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel, armbru
[-- Attachment #1: Type: text/plain, Size: 1054 bytes --]
On 09/13/2013 11:54 AM, Luiz Capitulino wrote:
> On Wed, 11 Sep 2013 17:27:58 -0600
> Eric Blake <eblake@redhat.com> wrote:
>
>> On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
>>> Simplify the text, fix some of the examples.
>>>
>>> - QEMU Monitor Protocol Specification - Version 0.1
>>> + QEMU Machine Protocol Specification
>>
>> Do we want a protocol version number? I guess if we ever add
>> capabilities, we can worry about it then.
>
> Yes, but I don't think we want it. This is the sole place where
> a version number appears and it's quite meaningless.
Indeed, capabilities are more powerful than version numbers, and since
the initial version already included capabilities, we already have as
much as we need to support any arbitrary future capabilities without
needing to add a version.
>
>>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
Hence this still stands :)
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes
2013-09-11 20:52 [Qemu-devel] [PATCH 0/6] QMP: re-organize documentation Luiz Capitulino
` (4 preceding siblings ...)
2013-09-11 20:52 ` [Qemu-devel] [PATCH 5/6] QMP: Update qmp-spec.txt Luiz Capitulino
@ 2013-09-11 20:52 ` Luiz Capitulino
2013-09-11 23:30 ` Eric Blake
5 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-11 20:52 UTC (permalink / raw)
To: qemu-devel; +Cc: armbru
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
docs/qmp/qmp-events.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index 39b6016..1e91f45 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -1,4 +1,4 @@
- QEMU Monitor Protocol Events
+ QEMU Machine Protocol Events
============================
BALLOON_CHANGE
@@ -173,7 +173,7 @@ Data:
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
NIC_RX_FILTER_CHANGED
------------------
+---------------------
The event is emitted once until the query command is executed,
the first event will always be emitted.
--
1.8.1.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes
2013-09-11 20:52 ` [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes Luiz Capitulino
@ 2013-09-11 23:30 ` Eric Blake
2013-09-13 18:01 ` Luiz Capitulino
0 siblings, 1 reply; 20+ messages in thread
From: Eric Blake @ 2013-09-11 23:30 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel, armbru
[-- Attachment #1: Type: text/plain, Size: 1267 bytes --]
On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
> docs/qmp/qmp-events.txt | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
> index 39b6016..1e91f45 100644
> --- a/docs/qmp/qmp-events.txt
> +++ b/docs/qmp/qmp-events.txt
> @@ -1,4 +1,4 @@
> - QEMU Monitor Protocol Events
> + QEMU Machine Protocol Events
> ============================
>
> BALLOON_CHANGE
> @@ -173,7 +173,7 @@ Data:
> "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
>
> NIC_RX_FILTER_CHANGED
> ------------------
> +---------------------
>
> The event is emitted once until the query command is executed,
> the first event will always be emitted.
>
Reviewed-by: Eric Blake <eblake@redhat.com>
But incomplete. DEVICE_DELETED has a too-long delimiter, GUEST_PANICKED
is out of order, and it's probably worth splitting SPICE_CONNECTED and
SPICE_DISCONNECTED into separate sections (matching VNC_CONNECTED and
VNC_DISCONNECTED).
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes
2013-09-11 23:30 ` Eric Blake
@ 2013-09-13 18:01 ` Luiz Capitulino
2013-09-13 18:16 ` Eric Blake
0 siblings, 1 reply; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-13 18:01 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, armbru
On Wed, 11 Sep 2013 17:30:48 -0600
Eric Blake <eblake@redhat.com> wrote:
> On 09/11/2013 02:52 PM, Luiz Capitulino wrote:
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> > docs/qmp/qmp-events.txt | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
> > index 39b6016..1e91f45 100644
> > --- a/docs/qmp/qmp-events.txt
> > +++ b/docs/qmp/qmp-events.txt
> > @@ -1,4 +1,4 @@
> > - QEMU Monitor Protocol Events
> > + QEMU Machine Protocol Events
> > ============================
> >
> > BALLOON_CHANGE
> > @@ -173,7 +173,7 @@ Data:
> > "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
> >
> > NIC_RX_FILTER_CHANGED
> > ------------------
> > +---------------------
> >
> > The event is emitted once until the query command is executed,
> > the first event will always be emitted.
> >
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
> But incomplete. DEVICE_DELETED has a too-long delimiter, GUEST_PANICKED
> is out of order,
Fixed those.
> and it's probably worth splitting SPICE_CONNECTED and
> SPICE_DISCONNECTED into separate sections (matching VNC_CONNECTED and
> VNC_DISCONNECTED).
This probably better done in a different patch. Will left for another day.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes
2013-09-13 18:01 ` Luiz Capitulino
@ 2013-09-13 18:16 ` Eric Blake
2013-09-13 18:20 ` Luiz Capitulino
0 siblings, 1 reply; 20+ messages in thread
From: Eric Blake @ 2013-09-13 18:16 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: qemu-devel, armbru
[-- Attachment #1: Type: text/plain, Size: 671 bytes --]
On 09/13/2013 12:01 PM, Luiz Capitulino wrote:
> On Wed, 11 Sep 2013 17:30:48 -0600
> Eric Blake <eblake@redhat.com> wrote:
>
>
>> and it's probably worth splitting SPICE_CONNECTED and
>> SPICE_DISCONNECTED into separate sections (matching VNC_CONNECTED and
>> VNC_DISCONNECTED).
>
> This probably better done in a different patch. Will left for another day.
In fact, such a better day is probably during the conversion from txt to
QMP (now that we have a proposal for how to use a discriminated qmp
union type for representing event types).
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 621 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] QMP: qmp-events.txt: minor fixes
2013-09-13 18:16 ` Eric Blake
@ 2013-09-13 18:20 ` Luiz Capitulino
0 siblings, 0 replies; 20+ messages in thread
From: Luiz Capitulino @ 2013-09-13 18:20 UTC (permalink / raw)
To: Eric Blake; +Cc: qemu-devel, armbru
On Fri, 13 Sep 2013 12:16:04 -0600
Eric Blake <eblake@redhat.com> wrote:
> On 09/13/2013 12:01 PM, Luiz Capitulino wrote:
> > On Wed, 11 Sep 2013 17:30:48 -0600
> > Eric Blake <eblake@redhat.com> wrote:
> >
> >
> >> and it's probably worth splitting SPICE_CONNECTED and
> >> SPICE_DISCONNECTED into separate sections (matching VNC_CONNECTED and
> >> VNC_DISCONNECTED).
> >
> > This probably better done in a different patch. Will left for another day.
>
> In fact, such a better day is probably during the conversion from txt to
> QMP (now that we have a proposal for how to use a discriminated qmp
> union type for representing event types).
Yeah.
^ permalink raw reply [flat|nested] 20+ messages in thread