aboutsummaryrefslogtreecommitdiff
path: root/python/qemu
AgeCommit message (Collapse)AuthorFilesLines
2022-01-21python/aqmp: add SocketAddrT to package rootJohn Snow1-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>
2022-01-21python/aqmp: copy type definitions from qmpJohn Snow2-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>
2022-01-21python/aqmp: handle asyncio.TimeoutError on execute()John Snow1-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>
2022-01-21python/aqmp: add __del__ method to legacy interfaceJohn Snow1-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>
2022-01-21python/aqmp: fix docstring typoJohn Snow1-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>
2022-01-10python: update type hints for mypy 0.930John Snow1-5/+1
Mypy 0.930, released Dec 22, changes the way argparse objects are considered. Crafting a definition that works under Python 3.6 and an older mypy alongside newer versions simultaneously is ... difficult, so... eh. Stub it out with an 'Any' definition to get the CI moving again. Oh well. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Beraldo Leal <bleal@redhat.com> Message-id: 20220110191349.1841027-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2022-01-10Python/aqmp: fix type definitions for mypy 0.920John Snow1-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>
2022-01-10python/aqmp: use absolute import statementJohn Snow1-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>
2021-11-22python/aqmp: fix send_fd_scm for python 3.6.xJohn Snow1-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>
2021-11-22python/machine: handle "fast" QEMU terminationsJohn Snow1-7/+12
In the case that the QEMU process actually launches -- but then dies so quickly that we can't establish a QMP connection to it -- QEMUMachine currently calls _post_shutdown() assuming that it never launched the VM process. This isn't true, though: it "merely" may have failed to establish a QMP connection and the process is in the middle of its own exit path. If we don't wait for the subprocess, the caller may get a bogus `None` return for .exitcode(). This behavior was observed from device-crash-test; after the switch to Async QMP, the timings were changed such that it was now seemingly possible to witness the failure of "vm.launch()" *prior* to the exitcode becoming available. The semantic of the `_launched` property is changed in this patch. Instead of representing the condition "launch() executed successfully", it will now represent "has forked a child process successfully". This way, wait() when called in the exit path won't become a no-op. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Willian Rampazzo <willianr@redhat.com> Message-id: 20211118204620.1897674-6-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-22python/machine: move more variable initializations to _pre_launchJohn Snow1-8/+8
No need to clear them only to set them later. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Willian Rampazzo <willianr@redhat.com> Message-id: 20211118204620.1897674-5-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-22python/machine: add instance disambiguator to default nicknameJohn Snow1-1/+1
If you create two instances of QEMUMachine(), they'll both create the same nickname by default -- which is not that helpful. Luckily, they'll both create unique temporary directories ... but due to user configuration, they may share logging and sockfile directories, meaning two instances can collide. The Python logging will also be quite confusing, with no differentiation between the two instances. Add an instance disambiguator (The memory address of the instance) to the default nickname to foolproof this in all cases. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Willian Rampazzo <willianr@redhat.com> Message-id: 20211118204620.1897674-4-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-22python/machine: remove _remove_monitor_sockfile propertyJohn Snow1-4/+1
It doesn't matter if it was the user or the class itself that specified where the sockfile should be created; the fact is that if we are using a sockfile here, we created it and we can clean it up. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Willian Rampazzo <willianr@redhat.com> Message-id: 20211118204620.1897674-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-22python/machine: add @sock_dir propertyJohn Snow1-4/+13
Analogous to temp_dir and log_dir, add a sock_dir property that defaults to @temp_dir -- instead of base_temp_dir -- when the user hasn't overridden the sock dir value in the initializer. This gives us a much more unique directory to put sockfiles in by default. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Willian Rampazzo <willianr@redhat.com> Message-id: 20211118204620.1897674-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-16python/aqmp: fix ConnectError string methodJohn Snow1-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>
2021-11-16python/aqmp: Fix disconnect during capabilities negotiationJohn Snow1-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>
2021-11-08tests/acceptance: rename tests acceptance to tests avocadoWillian Rampazzo3-3/+3
In the discussion about renaming the `tests/acceptance` [1], the conclusion was that the folders inside `tests` are related to the framework running the tests and not directly related to the type of the tests. This changes the folder to `tests/avocado` and adjusts the MAKEFILE, the CI related files and the documentation. [1] https://lists.gnu.org/archive/html/qemu-devel/2021-05/msg06553.html Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Signed-off-by: Willian Rampazzo <willianr@redhat.com> Message-Id: <20211105155354.154864-3-willianr@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
2021-11-01python, iotests: replace qmp with aqmpJohn Snow1-1/+6
Swap out the synchronous QEMUMonitorProtocol from qemu.qmp with the sync wrapper from qemu.aqmp instead. Add an escape hatch in the form of the environment variable QEMU_PYTHON_LEGACY_QMP which allows you to cajole QEMUMachine into using the old implementation, proving that both implementations work concurrently. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Message-id: 20211026175612.4127598-9-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-01python/aqmp: Create sync QMP wrapper for iotestsJohn Snow1-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>
2021-11-01python/aqmp: Remove scary messageJohn Snow1-12/+0
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>
2021-11-01python/machine: Handle QMP errors on close more meticulouslyJohn Snow1-6/+42
To use the AQMP backend, Machine just needs to be a little more diligent about what happens when closing a QMP connection. The operation is no longer a freebie in the async world; it may return errors encountered in the async bottom half on incoming message receipt, etc. (AQMP's disconnect, ultimately, serves as the quiescence point where all async contexts are gathered together, and any final errors reported at that point.) Because async QMP continues to check for messages asynchronously, it's almost certainly likely that the loop will have exited due to EOF after issuing the last 'quit' command. That error will ultimately be bubbled up when attempting to close the QMP connection. The manager class here then is free to discard it -- if it was expected. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-id: 20211026175612.4127598-3-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-11-01python/machine: remove has_quit argumentJohn Snow1-15/+19
If we spy on the QMP commands instead, we don't need callers to remember to pass it. Seems like a fair trade-off. The one slightly weird bit is overloading this instance variable for wait(), where we use it to mean "don't issue the qmp 'quit' command". This means that wait() will "fail" if the QEMU process does not terminate of its own accord. In most cases, we probably did already actually issue quit -- some iotests do this -- but in some others, we may be waiting for QEMU to terminate for some other reason, such as a test wherein we tell the guest (directly) to shut down. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-id: 20211026175612.4127598-2-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-10-12python, iotests: remove socket_scm_helperJohn Snow2-5/+0
It's not used anymore, now. 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-11-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-10-12python/qmp: add send_fd_scm directly to QEMUMonitorProtocolJohn Snow2-47/+18
It turns out you can do this directly from Python ... and because of this, you don't need to worry about setting the inheritability of the fds or spawning another process. Doing this is helpful because it allows QEMUMonitorProtocol to keep its file descriptor and socket object as private implementation details. /that/ is helpful in turn because it allows me to write a compatible, alternative implementation. 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-10-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-10-12python/qmp: clear events on get_events() callJohn Snow3-4/+4
All callers in the tree *already* clear the events after a call to get_events(). Do it automatically instead and update callsites to remove the manual clear call. These semantics are quite a bit easier to emulate with async QMP, and nobody appears to be abusing some emergent properties of what happens if you decide not to clear them, so let's dial down to the dumber, simpler thing. Specifically: callers of clear() right after a call to get_events() are more likely expressing their desire to not see any events they just retrieved, whereas callers of clear_events() not in relation to a recent call to pull_event/get_events are likely expressing their desire to simply drop *all* pending events straight onto the floor. In the sync world, this is safe enough; in the async world it's nearly impossible to promise that nothing happens between getting and clearing the events. Making the retrieval also clear the queue is vastly simpler. 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-9-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-10-12python/aqmp: Disable logging messages by defaultJohn Snow1-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>
2021-10-12python/aqmp: Reduce severity of EOFError-caused loop terminationsJohn Snow1-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>
2021-10-12python/aqmp: Add dict conversion method to Greeting objectJohn Snow1-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>
2021-10-12python/aqmp: add send_fd_scmJohn Snow1-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>
2021-10-12python/aqmp: Return cleared events from EventListener.clear()John Snow1-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>
2021-10-12python/aqmp: add .empty() method to EventListenerJohn Snow1-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>
2021-10-12python/aqmp: add greeting property to QMPClientJohn Snow1-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>
2021-09-27python/aqmp-tui: Add syntax highlightingG S Niteesh Babu1-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>
2021-09-27python/aqmp-tui: Add AQMP TUIG S Niteesh Babu1-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>
2021-09-27python/aqmp: add scary messageJohn Snow1-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>
2021-09-27python/aqmp: add asyncio_run compatibility wrapperJohn Snow1-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>
2021-09-27python/aqmp: add _raw() execution interfaceJohn Snow1-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>
2021-09-27python/aqmp: add execute() interfacesJohn Snow2-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>
2021-09-27python/aqmp: Add message routing to QMP protocolJohn Snow1-2/+120
Add the ability to handle and route messages in qmp_protocol.py. The interface for actually sending anything still isn't added until next commit. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-20-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add QMP protocol supportJohn Snow2-0/+266
The star of our show! Add most of the QMP protocol, sans support for actually executing commands. No problem, that happens in the next several commits. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-18-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add QMP event supportJohn Snow2-0/+708
This class was designed as a "mix-in" primarily so that the feature could be given its own treatment in its own python module. It gets quite a bit too long otherwise. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-16-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add well-known QMP object modelsJohn Snow1-0/+133
The QMP spec doesn't define very many objects that are iron-clad in their format, but there are a few. This module makes it trivial to validate them without relying on an external third-party library. Signed-off-by: John Snow <jsnow@redhat.com> Message-id: 20210915162955.333025-15-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add QMP Message formatJohn Snow2-1/+212
The Message class is here primarily to serve as a solid type to use for mypy static typing for unambiguous annotation and documentation. We can also stuff JSON serialization and deserialization into this class itself so it can be re-used even outside this infrastructure. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-14-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add AsyncProtocol._readline() methodJohn Snow1-0/+29
This is added as a courtesy: many protocols are line-based, including QMP. Putting it in AsyncProtocol lets us keep the QMP class implementation just a pinch more abstract. (And, if we decide to add a QTEST implementation later, it will need this, too. (Yes, I have a QTEST implementation.)) Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-13-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add _cb_inbound and _cb_outbound logging hooksJohn Snow1-4/+46
Add hooks designed to log/filter incoming/outgoing messages. The primary intent for these is to be able to support iotests which may want to log messages with specific filters for reproducible output. Another use is for plugging into Urwid frameworks; all messages in/out can be automatically added to a rendering list for the purposes of a qmp-shell like tool. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-12-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add configurable read buffer limitJohn Snow1-2/+16
QMP can transmit some pretty big messages, and the default limit of 64KB isn't sufficient. Make sure that we can configure it. Reported-by: G S Niteesh Babu <niteesh.gs@gmail.com> Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-11-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add AsyncProtocol.accept() methodJohn Snow1-4/+85
It's a little messier than connect, because it wasn't designed to accept *precisely one* connection. Such is life. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-10-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add logging to AsyncProtocolJohn Snow1-9/+73
Give the connection and the reader/writer tasks nicknames, and add logging statements throughout. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-9-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: Add logging utility helpersJohn Snow1-0/+56
Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-8-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
2021-09-27python/aqmp: add runstate state machine to AsyncProtocolJohn Snow2-5/+160
This serves a few purposes: 1. Protect interfaces when it's not safe to call them (via @require) 2. Add an interface by which an async client can determine if the state has changed, for the purposes of connection management. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-id: 20210915162955.333025-7-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>