scripts: qmp-shell: add transaction subshell
Add a special processing mode to craft transactions. By entering "transaction(" the shell will enter a special mode where each subsequent command will be saved as a transaction instead of executed as an individual command. The transaction can be submitted by entering ")" on a line by itself. Examples: Separate lines: (QEMU) transaction( TRANS> block-dirty-bitmap-add node=drive0 name=bitmap1 TRANS> block-dirty-bitmap-clear node=drive0 name=bitmap0 TRANS> ) With a transaction action included on the first line: (QEMU) transaction( block-dirty-bitmap-add node=drive0 name=bitmap2 TRANS> block-dirty-bitmap-add node=drive0 name=bitmap3 TRANS> ) As a one-liner, with just one transaction action: (QEMU) transaction( block-dirty-bitmap-add node=drive0 name=bitmap0 ) As a side-effect of this patch, blank lines are now parsed as no-ops, regardless of which shell mode you are in. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Tested-by: Kashyap Chamarthy <kchamart@redhat.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
parent
6092c3ecc4
commit
30bd6815ef
@ -73,6 +73,8 @@ class QMPShell(qmp.QEMUMonitorProtocol):
|
|||||||
self._greeting = None
|
self._greeting = None
|
||||||
self._completer = None
|
self._completer = None
|
||||||
self._pp = pp
|
self._pp = pp
|
||||||
|
self._transmode = False
|
||||||
|
self._actions = list()
|
||||||
|
|
||||||
def __get_address(self, arg):
|
def __get_address(self, arg):
|
||||||
"""
|
"""
|
||||||
@ -159,6 +161,36 @@ class QMPShell(qmp.QEMUMonitorProtocol):
|
|||||||
< command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
|
< command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
|
||||||
"""
|
"""
|
||||||
cmdargs = cmdline.split()
|
cmdargs = cmdline.split()
|
||||||
|
|
||||||
|
# Transactional CLI entry/exit:
|
||||||
|
if cmdargs[0] == 'transaction(':
|
||||||
|
self._transmode = True
|
||||||
|
cmdargs.pop(0)
|
||||||
|
elif cmdargs[0] == ')' and self._transmode:
|
||||||
|
self._transmode = False
|
||||||
|
if len(cmdargs) > 1:
|
||||||
|
raise QMPShellError("Unexpected input after close of Transaction sub-shell")
|
||||||
|
qmpcmd = { 'execute': 'transaction',
|
||||||
|
'arguments': { 'actions': self._actions } }
|
||||||
|
self._actions = list()
|
||||||
|
return qmpcmd
|
||||||
|
|
||||||
|
# Nothing to process?
|
||||||
|
if not cmdargs:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Parse and then cache this Transactional Action
|
||||||
|
if self._transmode:
|
||||||
|
finalize = False
|
||||||
|
action = { 'type': cmdargs[0], 'data': {} }
|
||||||
|
if cmdargs[-1] == ')':
|
||||||
|
cmdargs.pop(-1)
|
||||||
|
finalize = True
|
||||||
|
self.__cli_expr(cmdargs[1:], action['data'])
|
||||||
|
self._actions.append(action)
|
||||||
|
return self.__build_cmd(')') if finalize else None
|
||||||
|
|
||||||
|
# Standard command: parse and return it to be executed.
|
||||||
qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
|
qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
|
||||||
self.__cli_expr(cmdargs[1:], qmpcmd['arguments'])
|
self.__cli_expr(cmdargs[1:], qmpcmd['arguments'])
|
||||||
return qmpcmd
|
return qmpcmd
|
||||||
@ -171,6 +203,9 @@ class QMPShell(qmp.QEMUMonitorProtocol):
|
|||||||
print 'command format: <command-name> ',
|
print 'command format: <command-name> ',
|
||||||
print '[arg-name1=arg1] ... [arg-nameN=argN]'
|
print '[arg-name1=arg1] ... [arg-nameN=argN]'
|
||||||
return True
|
return True
|
||||||
|
# For transaction mode, we may have just cached the action:
|
||||||
|
if qmpcmd is None:
|
||||||
|
return True
|
||||||
resp = self.cmd_obj(qmpcmd)
|
resp = self.cmd_obj(qmpcmd)
|
||||||
if resp is None:
|
if resp is None:
|
||||||
print 'Disconnected'
|
print 'Disconnected'
|
||||||
@ -191,6 +226,11 @@ class QMPShell(qmp.QEMUMonitorProtocol):
|
|||||||
version = self._greeting['QMP']['version']['qemu']
|
version = self._greeting['QMP']['version']['qemu']
|
||||||
print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
|
print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
|
||||||
|
|
||||||
|
def get_prompt(self):
|
||||||
|
if self._transmode:
|
||||||
|
return "TRANS> "
|
||||||
|
return "(QEMU) "
|
||||||
|
|
||||||
def read_exec_command(self, prompt):
|
def read_exec_command(self, prompt):
|
||||||
"""
|
"""
|
||||||
Read and execute a command.
|
Read and execute a command.
|
||||||
@ -330,7 +370,7 @@ def main():
|
|||||||
die('Could not connect to %s' % addr)
|
die('Could not connect to %s' % addr)
|
||||||
|
|
||||||
qemu.show_banner()
|
qemu.show_banner()
|
||||||
while qemu.read_exec_command('(QEMU) '):
|
while qemu.read_exec_command(qemu.get_prompt()):
|
||||||
pass
|
pass
|
||||||
qemu.close()
|
qemu.close()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user