summaryrefslogtreecommitdiffstats
path: root/python/qemu/aqmp
Commit message (Collapse)AuthorAgeFilesLines
* python: rename qemu.aqmp to qemu.qmpJohn Snow2022-04-2112-4680/+0Star
| | | | | | | | | | | | | | | | | | | | | Now that we are fully switched over to the new QMP library, move it back over the old namespace. This is being done primarily so that we may upload this package simply as "qemu.qmp" without introducing confusion over whether or not "aqmp" is a new protocol or not. The trade-off is increased confusion inside the QEMU developer tree. Sorry! Note: the 'private' member "_aqmp" in legacy.py also changes to "_qmp"; not out of necessity, but just to remove any traces of the "aqmp" name. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Acked-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org> Message-id: 20220330172812.3427355-8-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: copy qmp docstrings to qemu.aqmp.legacyJohn Snow2022-04-211-8/+90
| | | | | | | | | | | | | | Copy the docstrings out of qemu.qmp, adjusting them as necessary to more accurately reflect the current state of this class. (Licensing: This is copying and modifying GPLv2-only licensed docstrings into a GPLv2-only file.) Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Message-id: 20220330172812.3427355-5-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: fully separate from qmp.QEMUMonitorProtocolJohn Snow2022-04-211-6/+31
| | | | | | | | | | | | | | | After this patch, qemu.aqmp.legacy.QEMUMonitorProtocol no longer inherits from qemu.qmp.QEMUMonitorProtocol. To do this, several inherited methods need to be explicitly re-defined. (Licensing: This is copying and modifying GPLv2-only code into a GPLv2-only file.) Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Message-id: 20220330172812.3427355-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: take QMPBadPortError and parse_address from qemu.qmpJohn Snow2022-04-212-6/+27
| | | | | | | | | | | | | Shift these definitions over from the qmp package to the async qmp package. (Licensing: this is a lateral move, from GPLv2 (only) to GPLv2 (only)) Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Message-id: 20220330172812.3427355-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp-tui: relicense as LGPLv2+John Snow2022-04-211-1/+1
| | | | | | | | | | | | | | | | | | | | | | aqmp-tui, the async QMP text user interface tool, is presently licensed as GPLv2+. I intend to include this tool as an add-on to an LGPLv2+ library package hosted on PyPI.org. I've selected LGPLv2+ to maximize compatibility with other licenses while retaining a copyleft license. To keep licensing matters simple, I'd like to relicense this tool as LGPLv2+ as well in order to keep the resultant license of the hosted release files simple -- even if library users won't "link against" this command line tool. Therefore, I am asking permission to loosen the license. Niteesh is effectively the sole author of this code, with scattered lines from myself. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: G S Niteesh Babu <niteesh.gs@gmail.com> Message-id: 20220325200438.2556381-5-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/qmp-shell: relicense as LGPLv2+John Snow2022-04-211-3/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | qmp-shell is presently licensed as GPLv2 (only). I intend to include this tool as an add-on to an LGPLv2+ library package hosted on PyPI.org. I've selected LGPLv2+ to maximize compatibility with other licenses while retaining a copyleft license. To keep licensing matters simple, I'd like to relicense this tool as LGPLv2+ as well in order to keep the resultant license of the hosted release files simple -- even if library users won't "link against" this command line tool. Therefore, I am asking permission from the current authors of this tool to loosen the license. At present, those people are: - John Snow (me!), 411/609 - Luiz Capitulino, Author, 97/609 - Daniel Berrangé, 81/609 - Eduardo Habkost, 10/609 - Marc-André Lureau, 6/609 - Fam Zheng, 3/609 - Cleber Rosa, 1/609 (All of which appear to have been written under redhat.com addresses.) Eduardo's fixes are largely automated from 2to3 conversion tools and may not necessarily constitute authorship, but his signature would put to rest any questions. Cleber's changes concern a single import statement change. Also won't hurt to ask. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Acked-by: Fam Zheng <fam@euphon.net> Acked-by: Luiz Capitulino <lcapitulino@redhat.com> Acked-by: Eduardo Habkost <eduardo@habkost.net> Acked-by: Daniel P. Berrangé <berrange@redhat.com> Acked-by: Cleber Rosa <crosa@redhat.com> Message-id: 20220325200438.2556381-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: relicense as LGPLv2+John Snow2022-04-211-3/+3
| | | | | | | | | | | | | | | | | | | | | | | I am the sole author of all of the async QMP code (python/qemu/aqmp) with the following exceptions: python/qemu/aqmp/qmp_shell.py and python/qemu/aqmp/legacy.py were written by Luiz Capitulino (et al) and are already licensed separately as GPLv2 (only). aqmp_tui.py was written by Niteesh Babu G S and is licensed as GPLv2+. I wish to relicense as LGPLv2+ in order to provide as much flexibility as I reasonably can, while retaining a copyleft license. It is my belief that LGPLv2+ is a suitable license for the Python ecosystem that aligns with the goals and philosophy of the QEMU project. The intent is to eventually drop legacy.py, leaving only library code that is LGPLv2+. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20220325200438.2556381-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add explicit GPLv2 license to legacy.pyJohn Snow2022-04-211-0/+11
| | | | | | | | | | | | | The legacy.py module is heavily based on the QMP module by Luiz Capitulino (et al) which is licensed as explicit GPLv2-only. The async QMP package is currently licensed similarly, but I intend to relicense the async package to the more flexible LGPLv2+. In preparation for that change, make the license on legacy.py explicit. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20220325200438.2556381-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: drop _bind_hack()John Snow2022-03-072-39/+4Star
| | | | | | | | | | | | | | | | | _bind_hack() was a quick fix to allow async QMP to call bind(2) prior to calling listen(2) and accept(2). This wasn't sufficient to fully address the race condition present in synchronous clients. With the race condition in legacy.py fixed (see the previous commit), there are no longer any users of _bind_hack(). Drop it. Fixes: b0b662bb2b3 Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-11-jsnow@redhat.com [Expanded commit message. --js] Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: fix race condition in legacy.pyJohn Snow2022-03-071-5/+2Star
| | | | | | | | | | | | | | | | | | | | | | | legacy.py provides a synchronous model. iotests frequently uses this paradigm: - create QMP client object - start QEMU process - await connection from QEMU process In the switch from sync to async QMP, the QMP client object stopped calling bind() and listen() during the QMP object creation step, which creates a race condition if the QEMU process dials in too quickly. With refactoring out of the way, restore the former behavior of calling bind() and listen() during __init__() to fix this race condition. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-10-jsnow@redhat.com [Expanded commit message. --js] Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add start_server() and accept() methodsJohn Snow2022-03-071-5/+62
| | | | | | | | | | | | | | | | | | | | | Add start_server() and accept() methods that can be used instead of start_server_and_accept() to allow more fine-grained control over the incoming connection process. (Eagle-eyed reviewers will surely notice that it's a bit weird that "CONNECTING" is a state that's shared between both the start_server() and connect() states. That's absolutely true, and it's very true that checking on the presence of _accepted as an indicator of state is a hack. That's also very certainly true. But ... this keeps client code an awful lot simpler, as it doesn't have to care exactly *how* the connection is being made, just that it *is*. Is it worth disrupting that simplicity in order to provide a better state guard on `accept()`? Hm.) Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-9-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: stop the server during disconnect()John Snow2022-03-071-1/+5
| | | | | | | | | | | | Before we allow the full separation of starting the server and accepting new connections, make sure that the disconnect cleans up the server and its new state, too. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-8-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: refactor _do_accept() into two distinct stepsJohn Snow2022-03-071-5/+24
| | | | | | | | | | | | | | | | Refactor _do_accept() into _do_start_server() and _do_accept(). As of this commit, the former calls the latter, but in subsequent commits they'll be split apart. (So please forgive the misnomer for _do_start_server(); it will live up to its name shortly, and the docstring will be updated then too. I'm just cutting down on some churn.) Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-7-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: squelch pylint warning for too many linesJohn Snow2022-03-071-0/+3
| | | | | | | | | | | I would really like to keep this under 1000 lines, I promise. Doesn't look like it's gonna happen. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-6-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: split _client_connected_cb() out as _incoming()John Snow2022-03-071-25/+58
| | | | | | | | | | | | | As part of disentangling the monolithic nature of _do_accept(), split out the incoming callback to prepare for factoring out the "wait for a peer" step. Namely, this means using an event signal we can wait on from outside of this method. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-5-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: remove _new_session and _establish_connectionJohn Snow2022-03-071-72/+45Star
| | | | | | | | | | | | | | | | | | | | | | | | | | | These two methods attempted to entirely envelop the logic of establishing a connection to a peer start to finish. However, we need to break apart the incoming connection step into more granular steps. We will no longer be able to reasonably constrain the logic inside of these helper functions. So, remove them - with _session_guard(), they no longer serve a real purpose. Although the public API doesn't change, the internal API does. Now that there are no intermediary methods between e.g. connect() and _do_connect(), there's no hook where the runstate is set. As a result, the test suite changes a little to cope with the new semantics of _do_accept() and _do_connect(). Lastly, take some pieces of the now-deleted docstrings and move them up to the public interface level. They were a little more detailed, and it won't hurt to keep them. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: rename 'accept()' to 'start_server_and_accept()'John Snow2022-03-072-3/+5
| | | | | | | | | | | | | | | | | | | Previously, I had a method named "accept()" that under-the-hood calls bind(2), listen(2) *and* accept(2). I meant this as a simplification and counterpart to the one-shot "connect()" method. This is confusing to readers who expect accept() to mean *just* accept(2). Since I need to split apart the "accept()" method into multiple methods anyway (one of which strongly resembling accept(2)), it feels pertinent to rename this method *now*. Rename this all-in-one method "start_server_and_accept()" instead. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add _session_guard()John Snow2022-03-071-27/+62
| | | | | | | | | | | | | | | | | | | | | In _new_session, there's a fairly complex except clause that's used to give semantic errors to callers of accept() and connect(). We need to create a new two-step replacement for accept(), so factoring out this piece of logic will be useful. Bolster the comments and docstring here to try and demystify what's going on in this fairly delicate piece of Python magic. (If we were using Python 3.7+, this would be an @asynccontextmanager. We don't have that very nice piece of magic, however, so this must take an Awaitable to manage the Exception contexts properly. We pay the price for platform compatibility.) Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220225205948.3693480-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python: support recording QMP session to a fileDaniel P. Berrangé2022-02-231-7/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When running QMP commands with very large response payloads, it is often not easy to spot the info you want. If we can save the response to a file then tools like 'grep' or 'jq' can be used to extract information. For convenience of processing, we merge the QMP command and response dictionaries together: { "arguments": {}, "execute": "query-kvm", "return": { "enabled": false, "present": true } } Example usage $ ./scripts/qmp/qmp-shell-wrap -l q.log -p -- ./build/qemu-system-x86_64 -display none Welcome to the QMP low-level shell! Connected (QEMU) query-kvm { "return": { "enabled": false, "present": true } } (QEMU) query-mice { "return": [ { "absolute": false, "current": true, "index": 2, "name": "QEMU PS/2 Mouse" } ] } $ jq --slurp '. | to_entries[] | select(.value.execute == "query-kvm") | .value.return.enabled' < q.log false Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220128161157.36261-3-berrange@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python: introduce qmp-shell-wrap convenience toolDaniel P. Berrangé2022-02-231-4/+61
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | With the current 'qmp-shell' tool developers must first spawn QEMU with a suitable -qmp arg and then spawn qmp-shell in a separate terminal pointing to the right socket. With 'qmp-shell-wrap' developers can ignore QMP sockets entirely and just pass the QEMU command and arguments they want. The program will listen on a UNIX socket and tell QEMU to connect QMP to that. For example, this: # qmp-shell-wrap -- qemu-system-x86_64 -display none Is roughly equivalent of running: # qemu-system-x86_64 -display none -qmp qmp-shell-1234 & # qmp-shell qmp-shell-1234 Except that 'qmp-shell-wrap' switches the socket peers around so that it is the UNIX socket server and QEMU is the socket client. This makes QEMU reliably go away when qmp-shell-wrap exits, closing the server socket. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 20220128161157.36261-2-berrange@redhat.com [Edited for rebase. --js] Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add socket bind step to legacy.pyJohn Snow2022-02-022-3/+41
| | | | | | | | | | | | | | | | | | | | | | | | The synchronous QMP library would bind to the server address during __init__(). The new library delays this to the accept() call, because binding occurs inside of the call to start_[unix_]server(), which is an async method -- so it cannot happen during __init__ anymore. Python 3.7+ adds the ability to create the server (and thus the bind() call) and begin the active listening in separate steps, but we don't have that functionality in 3.6, our current minimum. Therefore ... Add a temporary workaround that allows the synchronous version of the client to bind the socket in advance, guaranteeing that there will be a UNIX socket in the filesystem ready for the QEMU client to connect to without a race condition. (Yes, it's a bit ugly. Fixing it more nicely will have to wait until our minimum Python version is 3.7+.) Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-id: 20220201041134.1237016-5-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Fix negotiation with pre-"oob" QEMUJohn Snow2022-02-021-2/+2
| | | | | | | | | | | | QEMU versions prior to the "oob" capability *also* can't accept the "enable" keyword argument at all. Fix the handshake process with older QEMU versions. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-id: 20220201041134.1237016-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python: move qmp-shell under the AQMP packageJohn Snow2022-01-211-0/+537
| | | | | | Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com>
* python/qmp: switch qmp-shell to AQMPJohn Snow2022-01-211-0/+3
| | | | | | | | We have a replacement for async QMP, but it doesn't have feature parity yet. For now, then, port the old tool onto the new backend. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
* python/aqmp: rename AQMPError to QMPErrorJohn Snow2022-01-216-21/+21
| | | | | | | | | This is in preparation for renaming qemu.aqmp to qemu.qmp. I should have done this from this from the very beginning, but it's a convenient time to make sure this churn is taken care of. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
* python/aqmp: add SocketAddrT to package rootJohn Snow2022-01-211-1/+9
| | | | | | | | It's a commonly needed definition, it can be re-exported by the root. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com>
* python/aqmp: copy type definitions from qmpJohn Snow2022-01-212-8/+30
| | | | | | | | | | Copy the remaining type definitions from QMP into the qemu.aqmp.legacy module. Now, users that require the legacy interface don't need to import anything else but qemu.aqmp.legacy wrapper. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com>
* python/aqmp: handle asyncio.TimeoutError on execute()John Snow2022-01-211-2/+6
| | | | | | | | | | This exception can be injected into any await statement. If we are canceled via timeout, we want to clear the pending execution record on our way out. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
* python/aqmp: add __del__ method to legacy interfaceJohn Snow2022-01-211-0/+18
| | | | | | | | | | | | | | | | | | | | | | | asyncio can complain *very* loudly if you forget to back out of things gracefully before the garbage collector starts destroying objects that contain live references to asyncio Tasks. The usual fix is just to remember to call aqmp.disconnect(), but for the sake of the legacy wrapper and quick, one-off scripts where a graceful shutdown is not necessarily of paramount imporance, add a courtesy cleanup that will trigger prior to seeing screenfuls of confusing asyncio tracebacks. Note that we can't *always* save you from yourself; depending on when the GC runs, you might just seriously be out of luck. The best we can do in this case is to gently remind you to clean up after yourself. (Still much better than multiple pages of incomprehensible python warnings for the crime of forgetting to put your toys away.) Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Beraldo Leal <bleal@redhat.com>
* python/aqmp: fix docstring typoJohn Snow2022-01-211-1/+1
| | | | | | Reported-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Beraldo Leal <bleal@redhat.com>
* Python/aqmp: fix type definitions for mypy 0.920John Snow2022-01-111-2/+3
| | | | | | | | | | | | | | | | 0.920 (Released 2021-12-15) is not entirely happy with the way that I was defining _FutureT: qemu/aqmp/protocol.py:601: error: Item "object" of the upper bound "Optional[Future[Any]]" of type variable "_FutureT" has no attribute "done" Update it with something a little mechanically simpler that works better across a wider array of mypy versions. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20220110191349.1841027-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: use absolute import statementJohn Snow2022-01-111-1/+2
| | | | | | | | | | | | | | | pylint's dependency astroid appears to have bugs in 2.9.1 and 2.9.2 (Dec 31 and Jan 3) that appear to erroneously expect the qemu namespace to have an __init__.py file. astroid 2.9.3 (Jan 9) avoids that problem, but appears to not understand a relative import within a namespace package. Update the relative import - it was worth changing anyway, because these packages will eventually be packaged and distributed separately. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Message-id: 20220110191349.1841027-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: fix send_fd_scm for python 3.6.xJohn Snow2021-11-231-3/+6
| | | | | | | | | | | | | 3.6 doesn't play keepaway with the socket object, so we don't need to go fishing for it on this version. In fact, so long as 'sendmsg' is still available, it's probably preferable to just use that method and only go fishing for forbidden details when we absolutely have to. Reported-by: Thomas Huth <thuth@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Willian Rampazzo <willianr@redhat.com> Message-id: 20211118204620.1897674-8-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: fix ConnectError string methodJohn Snow2021-11-161-1/+5
| | | | | | | | | | | | | | | | | | | | When ConnectError is used to wrap an Exception that was initialized without an error message, we are treated to a traceback with a rubbish line like this: ... ConnectError: Failed to establish session: Correct this to use the name of an exception as a fallback message: ... ConnectError: Failed to establish session: EOFError Better! Signed-off-by: John Snow <jsnow@redhat.com> Reported-by: Thomas Huth <thuth@redhat.com> Tested-by: Thomas Huth <thuth@redhat.com> Message-id: 20211111143719.2162525-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Fix disconnect during capabilities negotiationJohn Snow2021-11-161-5/+13
| | | | | | | | | | | | | | | | | | | | | | | If we receive ConnectionResetError (ECONNRESET) while attempting to perform capabilities negotiation -- prior to the establishment of the async reader/writer tasks -- the disconnect function is not aware that we are in an error pathway. As a result, when attempting to close the StreamWriter, we'll see the same ConnectionResetError that caused us to initiate a disconnect in the first place, which will cause the disconnect task itself to fail, which emits a CRITICAL logging event. I still don't know if there's a smarter way to check to see if an exception received at this point is "the same" exception as the one that caused the initial disconnect, but for now the problem can be avoided by improving the error pathway detection in the exit path. Reported-by: Thomas Huth <thuth@redhat.com> Signed-off-by: John Snow <jsnow@redhat.com> Tested-by: Thomas Huth <thuth@redhat.com> Message-id: 20211111143719.2162525-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Create sync QMP wrapper for iotestsJohn Snow2021-11-011-0/+138
| | | | | | | | | | | | | | | This is a wrapper around the async QMPClient that mimics the old, synchronous QEMUMonitorProtocol class. It is designed to be interchangeable with the old implementation. It does not, however, attempt to mimic Exception compatibility. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Message-id: 20211026175612.4127598-8-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Remove scary messageJohn Snow2021-11-011-12/+0Star
| | | | | | | | | | | | | The scary message interferes with the iotests output. Coincidentally, if iotests works by removing this, then it's good evidence that we don't really need to scare people away from using it. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Message-id: 20211026175612.4127598-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Disable logging messages by defaultJohn Snow2021-10-121-0/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | AQMP is a library, and ideally it should not print error diagnostics unless a user opts into seeing them. By default, Python will print all WARNING, ERROR or CRITICAL messages to screen if no logging configuration has been created by a client application. In AQMP's case, ERROR logging statements are used to report additional detail about runtime failures that will also eventually be reported to the client library via an Exception, so these messages should not be rendered by default. (Why bother to have them at all, then? In async contexts, there may be multiple Exceptions and we are only able to report one of them back to the client application. It is not reasonably easy to predict ahead of time if one or more of these Exceptions will be squelched. Therefore, it's useful to log intermediate failures to help make sense of the ultimate, resulting failure.) Add a NullHandler that will suppress these messages until a client application opts into logging via logging.basicConfig or similar. Note that upon calling basicConfig(), this handler will *not* suppress these messages from being displayed by the client's configuration. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210923004938.3999963-8-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Reduce severity of EOFError-caused loop terminationsJohn Snow2021-10-121-2/+5
| | | | | | | | | | | | | | When we encounter an EOFError, we don't know if it's an "error" in the perspective of the user of the library yet. Therefore, we should not log it as an error. Reduce the severity of this logging message to "INFO" to indicate that it's something that we expect to occur during the normal operation of the library. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210923004938.3999963-7-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Add dict conversion method to Greeting objectJohn Snow2021-10-121-0/+13
| | | | | | | | | | | The iotests interface expects to return the greeting as a dict; AQMP offers it as a rich object. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210923004938.3999963-6-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add send_fd_scmJohn Snow2021-10-121-0/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add an implementation for send_fd_scm to the async QMP implementation. Like socket_scm_helper mentions, a non-empty payload is required for QEMU to process the ancillary data. A space is most useful because it does not disturb the parsing of subsequent JSON objects. A note on "voiding the warranty": Python 3.11 removes support for calling sendmsg directly from a transport's socket. There is no other interface for doing this, our use case is, I suspect, "quite unique". As far as I can tell, this is safe to do -- send_fd_scm is a synchronous function and we can be guaranteed that the async coroutines will *not* be running when it is invoked. In testing, it works correctly. I investigated quite thoroughly the possibility of creating my own asyncio Transport (The class that ultimately manages the raw socket object) so that I could manage the socket myself, but this is so wildly invasive and unportable I scrapped the idea. It would involve a lot of copy-pasting of various python utilities and classes just to re-create the same infrastructure, and for extremely little benefit. Nah. Just boldly void the warranty instead, while I try to follow up on https://bugs.python.org/issue43232 Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210923004938.3999963-5-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: Return cleared events from EventListener.clear()John Snow2021-10-121-2/+7
| | | | | | | | | | | | | | | | This serves two purposes: (1) It is now possible to discern whether or not clear() removed any event(s) from the queue with absolute certainty, and (2) It is now very easy to get a List of all pending events in one chunk, which is useful for the sync bridge. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 20210923004938.3999963-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add .empty() method to EventListenerJohn Snow2021-10-121-0/+6
| | | | | | | | | | | | | Synchronous clients may want to know if they're about to block waiting for an event or not. A method such as this is necessary to implement a compatible interface for the old QEMUMonitorProtocol using the new async internals. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 20210923004938.3999963-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add greeting property to QMPClientJohn Snow2021-10-121-0/+5
| | | | | | | | | | | Expose the greeting as a read-only property of QMPClient so it can be retrieved at-will. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 20210923004938.3999963-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp-tui: Add syntax highlightingG S Niteesh Babu2021-09-271-2/+34
| | | | | | | | | | | | | | | Add syntax highlighting for the incoming and outgoing QMP messages. This is achieved using the pygments module which was added in a previous commit. The current implementation is a really simple one which doesn't allow for any configuration. In future this has to be improved to allow for easier theme config using an external config of some sort. Signed-off-by: G S Niteesh Babu <niteesh.gs@gmail.com> Message-Id: <20210823220746.28295-6-niteesh.gs@gmail.com> Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp-tui: Add AQMP TUIG S Niteesh Babu2021-09-271-0/+620
| | | | | | | | | | | | | | | | Added AQMP TUI. Implements the follwing basic features: 1) Command transmission/reception. 2) Shows events asynchronously. 3) Shows server status in the bottom status bar. 4) Automatic retries on disconnects and error conditions. Also added type annotations and necessary pylint/mypy configurations. Signed-off-by: G S Niteesh Babu <niteesh.gs@gmail.com> Message-Id: <20210823220746.28295-3-niteesh.gs@gmail.com> Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add scary messageJohn Snow2021-09-271-0/+14
| | | | | | | | | Add a warning whenever AQMP is used to steer people gently away from using it for the time-being. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-24-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add asyncio_run compatibility wrapperJohn Snow2021-09-271-0/+19
| | | | | | | | | | As a convenience. It isn't used by the library itself, but it is used by the test suite. It will also come in handy for users of the library still on Python 3.6. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-23-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add _raw() execution interfaceJohn Snow2021-09-271-0/+51
| | | | | | | | | | | | | | This is added in anticipation of wanting it for a synchronous wrapper for the iotest interface. Normally, execute() and execute_msg() both raise QMP errors in the form of Python exceptions. Many iotests expect the entire reply as-is. To reduce churn there, add a private execution interface that will ease transition churn. However, I do not wish to encourage its use, so it will remain a private interface. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-22-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
* python/aqmp: add execute() interfacesJohn Snow2021-09-272-8/+198
| | | | | | | | | | | | | | | | Add execute() and execute_msg(). _execute() is split into _issue() and _reply() halves so that hypothetical subclasses of QMP that want to support different execution paradigms can do so. I anticipate a synchronous interface may have need of separating the send/reply phases. However, I do not wish to expose that interface here and want to actively discourage it, so they remain private interfaces. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-21-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>