summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Privoznik <mprivozn@redhat.com>2022-03-04 10:09:46 +0100
committerMichal Privoznik <mprivozn@redhat.com>2022-03-10 09:51:33 +0100
commit050ed3e6298ea89ed54eb06e1257dc801cee8cb8 (patch)
treebd39e28729ca5f2f3cd38bd5c5cca77cf1821f40
parenta80412bf8cdf9d222e2f730980720a5fcc7f0af4 (diff)
downloadlibvirt-python-050ed3e6298ea89ed54eb06e1257dc801cee8cb8.tar.gz
Implement virDomainQemuMonitorCommandWithFiles() override
With libvirt-8.2.0 there's a new API: virDomainQemuMonitorCommandWithFiles(). Since the API has both input and output arguments we need to provide an alternative implementation. Moreover, since FD passing works only on UNIX-like systems we can query the returned FDs for their flags and construct mode for python File object. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
-rwxr-xr-xgenerator.py1
-rw-r--r--libvirt-qemu-override.c118
-rw-r--r--libvirt-qemu-override.py31
3 files changed, 149 insertions, 1 deletions
diff --git a/generator.py b/generator.py
index e62abae..6bc5d56 100755
--- a/generator.py
+++ b/generator.py
@@ -626,6 +626,7 @@ qemu_skip_function = {
# "virDomainQemuAttach",
'virConnectDomainQemuMonitorEventRegister', # overridden in -qemu.py
'virConnectDomainQemuMonitorEventDeregister', # overridden in -qemu.py
+ 'virDomainQemuMonitorCommandWithFiles', # overridden in -qemu.py
}
# Generate C code, but skip python impl
diff --git a/libvirt-qemu-override.c b/libvirt-qemu-override.c
index ba2d308..a554498 100644
--- a/libvirt-qemu-override.c
+++ b/libvirt-qemu-override.c
@@ -20,6 +20,9 @@
#include "typewrappers.h"
#include "libvirt-utils.h"
#include "build/libvirt-qemu.h"
+#ifndef __CYGWIN__
+# include <fcntl.h>
+#endif
#ifndef __CYGWIN__
extern PyObject *PyInit_libvirtmod_qemu(void);
@@ -325,6 +328,118 @@ libvirt_qemu_virConnectDomainQemuMonitorEventDeregister(PyObject *self ATTRIBUTE
}
#endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */
+#if LIBVIR_CHECK_VERSION(8, 2, 0)
+static PyObject *
+libvirt_qemu_virDomainQemuMonitorCommandWithFiles(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ PyObject *pyobj_domain;
+ const char *cmd;
+ PyObject *pyobj_files;
+ unsigned int flags;
+ virDomainPtr domain;
+ unsigned int ninfiles;
+ int *infiles = NULL;
+ unsigned int noutfiles = 0;
+ int *outfiles = NULL;
+ char *result = NULL;
+ ssize_t i;
+ PyObject *py_outfiles = NULL;
+ PyObject *py_retval = NULL;
+ int c_retval;
+
+ if (!PyArg_ParseTuple(args,
+ (char *) "Os|OI:virDomainQemuMonitorCommandWithFiles",
+ &pyobj_domain, &cmd, &pyobj_files, &flags))
+ return NULL;
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ ninfiles = PyList_Size(pyobj_files);
+
+ if (VIR_ALLOC_N(infiles, ninfiles) < 0)
+ return PyErr_NoMemory();
+
+ for (i = 0; i < ninfiles; i++) {
+ PyObject *pyfd;
+ int fd;
+
+ pyfd = PyList_GetItem(pyobj_files, i);
+
+ if (libvirt_intUnwrap(pyfd, &fd) < 0)
+ goto cleanup;
+
+ infiles[i] = fd;
+ }
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_retval = virDomainQemuMonitorCommandWithFiles(domain, cmd, ninfiles, infiles,
+ &noutfiles, &outfiles, &result, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_retval < 0) {
+ py_retval = VIR_PY_NONE;
+ goto cleanup;
+ }
+
+ if (!(py_outfiles = PyList_New(0)) ||
+ !(py_retval = PyTuple_New(2))) {
+ goto error;
+ }
+
+ for (i = 0; i < noutfiles; i++) {
+ int fd = outfiles[i];
+ const char *mode = "r+b";
+
+ /* Since FD passing works only on UNIX-like systems, we can do this. */
+#ifndef __CYGWIN__
+ int fflags;
+
+ if ((fflags = fcntl(fd, F_GETFL)) < 0)
+ goto error;
+
+ switch (fflags & (O_ACCMODE | O_APPEND)) {
+ case O_RDONLY:
+ mode = "rb";
+ break;
+ case O_WRONLY:
+ mode = "wb";
+ break;
+ case O_RDWR:
+ mode = "r+b";
+ break;
+ case O_WRONLY | O_APPEND:
+ mode = "ab";
+ break;
+ case O_RDWR | O_APPEND:
+ mode = "a+b";
+ break;
+ }
+#endif
+
+ VIR_PY_LIST_APPEND_GOTO(py_outfiles, PyFile_FromFd(fd, NULL, mode, 0, NULL, NULL, NULL, 1), error);
+ }
+
+ VIR_PY_TUPLE_SET_GOTO(py_retval, 0, libvirt_charPtrWrap(result), error);
+ VIR_PY_TUPLE_SET_GOTO(py_retval, 1, py_outfiles, error);
+ /* stolen by py_retval */
+ py_outfiles = NULL;
+
+ cleanup:
+ Py_XDECREF(py_outfiles);
+ VIR_FREE(result);
+ VIR_FREE(outfiles);
+ VIR_FREE(infiles);
+ return py_retval;
+
+ error:
+ while (noutfiles > 0) {
+ VIR_FORCE_CLOSE(outfiles[--noutfiles]);
+ }
+ Py_CLEAR(py_retval);
+ goto cleanup;
+}
+#endif /* LIBVIR_CHECK_VERSION(8, 2, 0) */
+
/************************************************************************
* *
* The registration stuff *
@@ -340,6 +455,9 @@ static PyMethodDef libvirtQemuMethods[] = {
{(char *) "virConnectDomainQemuMonitorEventRegister", libvirt_qemu_virConnectDomainQemuMonitorEventRegister, METH_VARARGS, NULL},
{(char *) "virConnectDomainQemuMonitorEventDeregister", libvirt_qemu_virConnectDomainQemuMonitorEventDeregister, METH_VARARGS, NULL},
#endif /* LIBVIR_CHECK_VERSION(1, 2, 3) */
+#if LIBVIR_CHECK_VERSION(8, 2, 0)
+ {(char *) "virDomainQemuMonitorCommandWithFiles", libvirt_qemu_virDomainQemuMonitorCommandWithFiles, METH_VARARGS, NULL},
+#endif /* LIBVIR_CHECK_VERSION(8, 2, 0) */
{NULL, NULL, 0, NULL}
};
diff --git a/libvirt-qemu-override.py b/libvirt-qemu-override.py
index fae1db7..600dc30 100644
--- a/libvirt-qemu-override.py
+++ b/libvirt-qemu-override.py
@@ -1,5 +1,5 @@
# Manually written part of python bindings for libvirt-qemu
-from typing import Any, Callable, Dict
+from typing import Any, Callable, Dict, List, IO
def _dispatchQemuMonitorEventCallback(conn: libvirt.virConnect, dom: libvirt.virDomain, event: str, seconds: int, micros: int, details: str, cbData: Dict[str, Any]) -> int:
@@ -38,3 +38,32 @@ def qemuMonitorEventRegister(conn: libvirt.virConnect, dom: libvirt.virDomain, e
raise libvirt.libvirtError('virConnectDomainQemuMonitorEventRegister() failed')
conn.qemuMonitorEventCallbackID[ret] = opaque # type: ignore
return ret
+
+def qemuMonitorCommandWithFiles(domain: libvirt.virDomain, cmd: str, files: List[int] = [], flags: int = 0) -> (str, List[IO]):
+ """This API is QEMU specific, so it will only work with hypervisor
+ connections to the QEMU driver with local connections using the unix
+ socket.
+
+ Send an arbitrary monitor command @cmd with file descriptors @files to
+ domain through the QEMU monitor and optionally return a list of files
+ in the returned tuple. There are several requirements to safely
+ and successfully use this API:
+
+ - A @cmd that queries state without making any modifications is safe
+ - A @cmd that alters state that is also tracked by libvirt is unsafe,
+ and may cause libvirtd to crash
+ - A @cmd that alters state not tracked by the current version of
+ libvirt is possible as a means to test new qemu features before
+ they have support in libvirt, but no guarantees are made to safety
+
+ If VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP is set, the command is considered to
+ be a human monitor command and libvirt will automatically convert it into
+ QMP if needed. In that case the @result will also be converted back from
+ QMP.
+
+ Returns a tuple consisting of the string output from @cmd and a list of
+ files respectively."""
+ ret = libvirtmod_qemu.virDomainQemuMonitorCommandWithFiles(domain._o, cmd, files, flags)
+ if ret is None:
+ raise libvirt.libvirtError('virDomainQemuMonitorCommandWithFiles() failed')
+ return ret