[libvirt] [python PATCH v2 0/5] Implement new APIs

new in v2: - moved function to appropriate place in libvirt-override.c - fixed generator to resolve enum reference - fixed memory leak in virDomainListGetStats and sanyti test - implemented API for virDomainBlockCopy Pavel Hrdina (3): generator: resolve one level of enum reference API: Implement bindings for virDomainListGetStats Implement API bindings for virDomainBlockCopy Peter Krempa (2): API: Skip 'virDomainStatsRecordListFree' API: Implement bindings for virConnectGetAllDomainStats generator.py | 20 ++++- libvirt-override-api.xml | 10 +++ libvirt-override-virConnect.py | 100 +++++++++++++++++++++++ libvirt-override.c | 180 +++++++++++++++++++++++++++++++++++++++++ sanitytest.py | 6 ++ 5 files changed, 315 insertions(+), 1 deletion(-) -- 1.8.5.5

In the libvirt.h we have one enum defined by references from another enum and it leads in wrong order of definitons in python code. To prevent this we should resolve that references before we generate the python code. For now we have only one level of references so we will count with that in the generator but we should update it in the future to be more flexible. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/generator.py b/generator.py index a12c52b..0d41e20 100755 --- a/generator.py +++ b/generator.py @@ -1785,12 +1785,26 @@ def buildWrappers(module): value = float('inf') return value + # Resolve only one level of reference + def resolveEnum(enum, data): + for name,val in enum.items(): + try: + int(val) + except ValueError: + enum[name] = data[val] + return enum + enumvals = list(enums.items()) + # convert list of dicts to one dict + enumData = {} + for type,enum in enumvals: + enumData.update(enum) + if enumvals is not None: enumvals.sort(key=lambda x: x[0]) for type,enum in enumvals: classes.write("# %s\n" % type) - items = list(enum.items()) + items = list(resolveEnum(enum, enumData).items()) items.sort(key=enumsSortKey) if items[-1][0].endswith('_LAST'): del items[-1] -- 1.8.5.5

On 09/01/14 22:18, Pavel Hrdina wrote:
In the libvirt.h we have one enum defined by references from another enum and it leads in wrong order of definitons in python code. To prevent this we should resolve that references before we generate the python code.
For now we have only one level of references so we will count with that in the generator but we should update it in the future to be more flexible.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/generator.py b/generator.py index a12c52b..0d41e20 100755 --- a/generator.py +++ b/generator.py @@ -1785,12 +1785,26 @@ def buildWrappers(module): value = float('inf') return value
+ # Resolve only one level of reference
We can make it recursive later if necessary.
+ def resolveEnum(enum, data): + for name,val in enum.items(): + try: + int(val) + except ValueError: + enum[name] = data[val] + return enum + enumvals = list(enums.items()) + # convert list of dicts to one dict + enumData = {} + for type,enum in enumvals: + enumData.update(enum)
Update shouldn't ever update a key as it would trigger an error when compiling the library code before we get here.
+ if enumvals is not None: enumvals.sort(key=lambda x: x[0]) for type,enum in enumvals: classes.write("# %s\n" % type) - items = list(enum.items()) + items = list(resolveEnum(enum, enumData).items()) items.sort(key=enumsSortKey) if items[-1][0].endswith('_LAST'): del items[-1]
ACK Peter

From: Peter Krempa <pkrempa@redhat.com> The new API function doesn't make sense to be exported in python. The bindings will return native types instead of the struct array. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + sanitytest.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/generator.py b/generator.py index 0d41e20..c4c12df 100755 --- a/generator.py +++ b/generator.py @@ -571,6 +571,7 @@ skip_function = ( "virTypedParamsGetULLong", 'virNetworkDHCPLeaseFree', # only useful in C, python code uses list + 'virDomainStatsRecordListFree', # only useful in C, python uses dict ) lxc_skip_function = ( diff --git a/sanitytest.py b/sanitytest.py index 4f4a648..10cf9f0 100644 --- a/sanitytest.py +++ b/sanitytest.py @@ -81,6 +81,9 @@ for cname in wantfunctions: if name[0:23] == "virNetworkDHCPLeaseFree": continue + if name[0:28] == "virDomainStatsRecordListFree": + continue + # These aren't functions, they're callback signatures if name in ["virConnectAuthCallbackPtr", "virConnectCloseFunc", "virStreamSinkFunc", "virStreamSourceFunc", "virStreamEventCallback", -- 1.8.5.5

On 09/01/14 22:18, Pavel Hrdina wrote:
From: Peter Krempa <pkrempa@redhat.com>
The new API function doesn't make sense to be exported in python. The bindings will return native types instead of the struct array.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + sanitytest.py | 3 +++ 2 files changed, 4 insertions(+)
diff --git a/sanitytest.py b/sanitytest.py index 4f4a648..10cf9f0 100644 --- a/sanitytest.py +++ b/sanitytest.py @@ -81,6 +81,9 @@ for cname in wantfunctions: if name[0:23] == "virNetworkDHCPLeaseFree": continue
+ if name[0:28] == "virDomainStatsRecordListFree": + continue +
Thanks for catching this. I didn't run the sanity test :/
# These aren't functions, they're callback signatures if name in ["virConnectAuthCallbackPtr", "virConnectCloseFunc", "virStreamSinkFunc", "virStreamSourceFunc", "virStreamEventCallback",
ACK, Peter

From: Peter Krempa <pkrempa@redhat.com> Implement the function by returning a list of tuples instead the array of virDomainStatsRecords and store the typed parameters as dict. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + libvirt-override-virConnect.py | 53 +++++++++++++++++++++++ libvirt-override.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/generator.py b/generator.py index c4c12df..3fc7db2 100755 --- a/generator.py +++ b/generator.py @@ -507,6 +507,7 @@ skip_function = ( 'virConnectListAllNodeDevices', # overridden in virConnect.py 'virConnectListAllNWFilters', # overridden in virConnect.py 'virConnectListAllSecrets', # overridden in virConnect.py + 'virConnectGetAllDomainStats', # overridden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/libvirt-override-virConnect.py b/libvirt-override-virConnect.py index 31d71a3..c4c400a 100644 --- a/libvirt-override-virConnect.py +++ b/libvirt-override-virConnect.py @@ -383,3 +383,56 @@ if ret is None:raise libvirtError('virDomainCreateXMLWithFiles() failed', conn=self) __tmp = virDomain(self,_obj=ret) return __tmp + + def getAllDomainStats(self, stats = 0, flags=0): + """Query statistics for all domains on a given connection. + + Report statistics of various parameters for a running VM according to @stats + field. The statistics are returned as an array of structures for each queried + domain. The structure contains an array of typed parameters containing the + individual statistics. The typed parameter name for each statistic field + consists of a dot-separated string containing name of the requested group + followed by a group specific description of the statistic value. + + The statistic groups are enabled using the @stats parameter which is a + binary-OR of enum virDomainStatsTypes. The following groups are available + (although not necessarily implemented for each hypervisor): + + VIR_DOMAIN_STATS_STATE: Return domain state and reason for entering that + state. The typed parameter keys are in this format: + "state.state" - state of the VM, returned as int from virDomainState enum + "state.reason" - reason for entering given state, returned as int from + virDomain*Reason enum corresponding to given state. + + Using 0 for @stats returns all stats groups supported by the given + hypervisor. + + Specifying VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS as @flags makes + the function return error in case some of the stat types in @stats were + not recognized by the daemon. + + Similarly to virConnectListAllDomains, @flags can contain various flags to + filter the list of domains to provide stats for. + + VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE selects online domains while + VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE selects offline ones. + + VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT and + VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT allow to filter the list + according to their persistence. + + To filter the list of VMs by domain state @flags can contain + VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING, + VIR_CONNECT_GET_ALL_DOMAINS_STATS_PAUSED, + VIR_CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF and/or + VIR_CONNECT_GET_ALL_DOMAINS_STATS_OTHER for all other states. """ + ret = libvirtmod.virConnectGetAllDomainStats(self._o, stats, flags) + if ret is None: + raise libvirtError("virConnectGetAllDomainStats() failed", conn=self) + + retlist = list() + for elem in ret: + record = (virDomain(self, _obj=elem[0]) , elem[1]) + retlist.append(record) + + return retlist diff --git a/libvirt-override.c b/libvirt-override.c index b2271ae..2da43ab 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -7955,6 +7955,98 @@ libvirt_virNetworkGetDHCPLeases(PyObject *self ATTRIBUTE_UNUSED, #endif /* LIBVIR_CHECK_VERSION(1, 2, 6) */ +#if LIBVIR_CHECK_VERSION(1, 2, 8) + +static PyObject * +convertDomainStatsRecord(virDomainStatsRecordPtr *records, + int nrecords) +{ + PyObject *py_retval; + PyObject *py_record; + PyObject *py_record_domain; + PyObject *py_record_stats; + size_t i; + + if (!(py_retval = PyList_New(nrecords))) + return NULL; + + for (i = 0; i < nrecords; i++) { + if (!(py_record = PyTuple_New(2))) + goto error; + + /* libvirt_virDomainPtrWrap steals the object */ + virDomainRef(records[i]->dom); + if (!(py_record_domain = libvirt_virDomainPtrWrap(records[i]->dom))) { + virDomainFree(records[i]->dom); + goto error; + } + + if (!(py_record_stats = getPyVirTypedParameter(records[i]->params, + records[i]->nparams))) + goto error; + + if (PyTuple_SetItem(py_record, 0, py_record_domain) < 0) + goto error; + + py_record_domain = NULL; + + if (PyTuple_SetItem(py_record, 1, py_record_stats) < 0) + goto error; + + py_record_stats = NULL; + + if (PyList_SetItem(py_retval, i, py_record) < 0) + goto error; + + py_record = NULL; + } + + return py_retval; + + error: + Py_XDECREF(py_retval); + Py_XDECREF(py_record); + Py_XDECREF(py_record_domain); + Py_XDECREF(py_record_stats); + return NULL; +} + + +static PyObject * +libvirt_virConnectGetAllDomainStats(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval; + virConnectPtr conn; + virDomainStatsRecordPtr *records; + int nrecords; + unsigned int flags; + unsigned int stats; + + if (!PyArg_ParseTuple(args, (char *)"Oii:virConnectGetAllDomainStats", + &pyobj_conn, &stats, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + nrecords = virConnectGetAllDomainStats(conn, stats, &records, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (nrecords < 0) + return VIR_PY_NONE; + + if (!(py_retval = convertDomainStatsRecord(records, nrecords))) + py_retval = VIR_PY_NONE; + + cleanup: + virDomainStatsRecordListFree(records); + + return py_retval; +} + +#endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ + /************************************************************************ * * * The registration stuff * @@ -8140,6 +8232,9 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virNodeGetFreePages", libvirt_virNodeGetFreePages, METH_VARARGS, NULL}, {(char *) "virNetworkGetDHCPLeases", libvirt_virNetworkGetDHCPLeases, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 6) */ +#if LIBVIR_CHECK_VERSION(1, 2, 8) + {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, +#endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} }; -- 1.8.5.5

On 09/01/14 22:18, Pavel Hrdina wrote:
From: Peter Krempa <pkrempa@redhat.com>
Implement the function by returning a list of tuples instead the array of virDomainStatsRecords and store the typed parameters as dict.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + libvirt-override-virConnect.py | 53 +++++++++++++++++++++++ libvirt-override.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+)
Well, looks like you didn't change this one and as you've ACKed it in v1 it should stand. Peter

Implement the function by returning a list of tuples instead the array of virDomainStatsRecords and store the typed parameters as dict. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + libvirt-override-virConnect.py | 47 ++++++++++++++++++++++++++++++++++++++ libvirt-override.c | 52 ++++++++++++++++++++++++++++++++++++++++++ sanitytest.py | 3 +++ 4 files changed, 103 insertions(+) diff --git a/generator.py b/generator.py index 3fc7db2..1daf866 100755 --- a/generator.py +++ b/generator.py @@ -508,6 +508,7 @@ skip_function = ( 'virConnectListAllNWFilters', # overridden in virConnect.py 'virConnectListAllSecrets', # overridden in virConnect.py 'virConnectGetAllDomainStats', # overridden in virConnect.py + 'virDomainListGetStats', # overriden in virConnect.py 'virStreamRecvAll', # Pure python libvirt-override-virStream.py 'virStreamSendAll', # Pure python libvirt-override-virStream.py diff --git a/libvirt-override-virConnect.py b/libvirt-override-virConnect.py index c4c400a..218f266 100644 --- a/libvirt-override-virConnect.py +++ b/libvirt-override-virConnect.py @@ -436,3 +436,50 @@ retlist.append(record) return retlist + + def domainListGetStats(self, doms, stats=0, flags=0): + """ Query statistics for given domains. + + Report statistics of various parameters for a running VM according to @stats + field. The statistics are returned as an array of structures for each queried + domain. The structure contains an array of typed parameters containing the + individual statistics. The typed parameter name for each statistic field + consists of a dot-separated string containing name of the requested group + followed by a group specific description of the statistic value. + + The statistic groups are enabled using the @stats parameter which is a + binary-OR of enum virDomainStatsTypes. The following groups are available + (although not necessarily implemented for each hypervisor): + + VIR_DOMAIN_STATS_STATE: Return domain state and reason for entering that + state. The typed parameter keys are in this format: + "state.state" - state of the VM, returned as int from virDomainState enum + "state.reason" - reason for entering given state, returned as int from + virDomain*Reason enum corresponding to given state. + + Using 0 for @stats returns all stats groups supported by the given + hypervisor. + + Specifying VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS as @flags makes + the function return error in case some of the stat types in @stats were + not recognized by the daemon. + + Get statistics about domains provided as a list in @doms. @stats is + a bit field selecting requested statistics types.""" + domlist = list() + for dom in doms: + if not isinstance(dom, virDomain): + raise libvirtError("domain list contains non-domain elements", conn=self) + + domlist.append(dom._o) + + ret = libvirtmod.virDomainListGetStats(self._o, domlist, stats, flags) + if ret is None: + raise libvirtError("virDomainListGetStats() failed", conn=self) + + retlist = list() + for elem in ret: + record = (virDomain(self, _obj=elem[0]) , elem[1]) + retlist.append(record) + + return retlist diff --git a/libvirt-override.c b/libvirt-override.c index 2da43ab..569778d 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -8045,6 +8045,57 @@ libvirt_virConnectGetAllDomainStats(PyObject *self ATTRIBUTE_UNUSED, return py_retval; } + +static PyObject * +libvirt_virDomainListGetStats(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *pyobj_conn; + PyObject *py_retval; + PyObject *py_domlist; + virConnectPtr conn; + virDomainStatsRecordPtr *records = NULL; + virDomainPtr *doms = NULL; + int nrecords; + int ndoms; + size_t i; + unsigned int flags; + unsigned int stats; + + if (!PyArg_ParseTuple(args, (char *)"OOii:virDomainListGetStats", + &pyobj_conn, &py_domlist, &stats, &flags)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + if (PyList_Check(py_domlist)) { + ndoms = PyList_Size(py_domlist); + + if (VIR_ALLOC_N(doms, ndoms + 1) < 0) + return PyErr_NoMemory(); + + for (i = 0; i < ndoms; i++) + doms[i] = PyvirDomain_Get(PyList_GetItem(py_domlist, i)); + } + + LIBVIRT_BEGIN_ALLOW_THREADS; + nrecords = virDomainListGetStats(doms, stats, &records, flags); + LIBVIRT_END_ALLOW_THREADS; + + if (nrecords < 0) { + py_retval = VIR_PY_NONE; + goto cleanup; + } + + if (!(py_retval = convertDomainStatsRecord(records, nrecords))) + py_retval = VIR_PY_NONE; + + cleanup: + virDomainStatsRecordListFree(records); + VIR_FREE(doms); + + return py_retval; +} + #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ /************************************************************************ @@ -8234,6 +8285,7 @@ static PyMethodDef libvirtMethods[] = { #endif /* LIBVIR_CHECK_VERSION(1, 2, 6) */ #if LIBVIR_CHECK_VERSION(1, 2, 8) {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, + {(char *) "virDomainListGetStats", libvirt_virDomainListGetStats, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} }; diff --git a/sanitytest.py b/sanitytest.py index 10cf9f0..3c1568b 100644 --- a/sanitytest.py +++ b/sanitytest.py @@ -84,6 +84,9 @@ for cname in wantfunctions: if name[0:28] == "virDomainStatsRecordListFree": continue + if name[0:21] == "virDomainListGetStats": + name = "virConnectDomainListGetStats" + # These aren't functions, they're callback signatures if name in ["virConnectAuthCallbackPtr", "virConnectCloseFunc", "virStreamSinkFunc", "virStreamSourceFunc", "virStreamEventCallback", -- 1.8.5.5

On 09/01/14 22:18, Pavel Hrdina wrote:
Implement the function by returning a list of tuples instead the array of virDomainStatsRecords and store the typed parameters as dict.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + libvirt-override-virConnect.py | 47 ++++++++++++++++++++++++++++++++++++++ libvirt-override.c | 52 ++++++++++++++++++++++++++++++++++++++++++ sanitytest.py | 3 +++ 4 files changed, 103 insertions(+)
The changes look good to me, so if no one else will object ACK Peter

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + libvirt-override-api.xml | 10 ++++++++++ libvirt-override.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/generator.py b/generator.py index 1daf866..a798274 100755 --- a/generator.py +++ b/generator.py @@ -464,6 +464,7 @@ skip_impl = ( 'virConnectGetCPUModelNames', 'virNodeGetFreePages', 'virNetworkGetDHCPLeases', + 'virDomainBlockCopy', ) lxc_skip_impl = ( diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml index 09bbbf8..f0049d7 100644 --- a/libvirt-override-api.xml +++ b/libvirt-override-api.xml @@ -640,5 +640,15 @@ <arg name='flags' type='unsigned int' info='unused, pass 0'/> <return type='char *' info="list of leases"/> </function> + <function name="virDomainBlockCopy" file="python"> + <info>Copy the guest-visible contents of a disk image to a new file described by destxml</info> + <arg name='dom' type='virDomainPtr' info='pointer to domain object'/> + <arg name='disk' type='const char *' info='path to the block device, or device shorthand'/> + <arg name='destxml' type='const char *' info='XML description of the copy destination'/> + <arg name='params' type='virTypedParameterPtr' info='pointer to block copy parameter object, or NULL'/> + <arg name='nparams' type='int' info='nuber of block copy parameters (this value can be the same or less then the number of parameters supported)'/> + <arg name='flags' type='unsigned int' info='bitwise-OR of virDomainBlockCopyFlags'/> + <return type='int' info='0 if the operation has started, -1 on failure'/> + </function> </symbols> </api> diff --git a/libvirt-override.c b/libvirt-override.c index 569778d..733a16f 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -8096,6 +8096,38 @@ libvirt_virDomainListGetStats(PyObject *self ATTRIBUTE_UNUSED, return py_retval; } + +static PyObject * +libvirt_virDomainBlockCopy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) +{ + PyObject *pyobj_dom = NULL; + PyObject *pyobj_dict = NULL; + + virDomainPtr dom; + char *disk = NULL; + char *destxml = NULL; + virTypedParameterPtr params; + int nparams; + unsigned int flags; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *) "OzzOii:virDomainBlockCopy", + &pyobj_dom, &disk, &destxml, &pyobj_dict, &nparams, + &flags)) + return VIR_PY_INT_FAIL; + + if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, NULL, 0) < 0) + return VIR_PY_INT_FAIL; + + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainBlockCopy(dom, disk, destxml, params, nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + return libvirt_intWrap(c_retval); +} + #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ /************************************************************************ @@ -8286,6 +8318,7 @@ static PyMethodDef libvirtMethods[] = { #if LIBVIR_CHECK_VERSION(1, 2, 8) {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, {(char *) "virDomainListGetStats", libvirt_virDomainListGetStats, METH_VARARGS, NULL}, + {(char *) "virDomainBlockCopy", libvirt_virDomainBlockCopy, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} }; -- 1.8.5.5

On 09/01/14 22:18, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- generator.py | 1 + libvirt-override-api.xml | 10 ++++++++++ libvirt-override.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+)
diff --git a/generator.py b/generator.py index 1daf866..a798274 100755 --- a/generator.py +++ b/generator.py @@ -464,6 +464,7 @@ skip_impl = ( 'virConnectGetCPUModelNames', 'virNodeGetFreePages', 'virNetworkGetDHCPLeases', + 'virDomainBlockCopy', )
lxc_skip_impl = ( diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml index 09bbbf8..f0049d7 100644 --- a/libvirt-override-api.xml +++ b/libvirt-override-api.xml @@ -640,5 +640,15 @@ <arg name='flags' type='unsigned int' info='unused, pass 0'/> <return type='char *' info="list of leases"/> </function> + <function name="virDomainBlockCopy" file="python"> + <info>Copy the guest-visible contents of a disk image to a new file described by destxml</info> + <arg name='dom' type='virDomainPtr' info='pointer to domain object'/> + <arg name='disk' type='const char *' info='path to the block device, or device shorthand'/> + <arg name='destxml' type='const char *' info='XML description of the copy destination'/> + <arg name='params' type='virTypedParameterPtr' info='pointer to block copy parameter object, or NULL'/> + <arg name='nparams' type='int' info='nuber of block copy parameters (this value can be the same or less then the number of parameters supported)'/>
Humm, the python generator doesn't have nice typed parameter support. This actually wouldn't be usable from python as this python method is generated: def blockCopy(self, disk, destxml, params, nparams, flags=0): """Copy the guest-visible contents of a disk image to a new file described by destxml """ ret = libvirtmod.virDomainBlockCopy(self._o, disk, destxml, params, nparams, flags) if ret == -1: raise libvirtError ('virDomainBlockCopy() failed', dom=self) return ret As there is no nice way to construct a typed parameter in python we usually convert them to or from dicts. This will require you to write the python impl too and ...
+ <arg name='flags' type='unsigned int' info='bitwise-OR of virDomainBlockCopyFlags'/> + <return type='int' info='0 if the operation has started, -1 on failure'/> + </function> </symbols> </api> diff --git a/libvirt-override.c b/libvirt-override.c index 569778d..733a16f 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -8096,6 +8096,38 @@ libvirt_virDomainListGetStats(PyObject *self ATTRIBUTE_UNUSED, return py_retval; }
+ +static PyObject * +libvirt_virDomainBlockCopy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) +{ + PyObject *pyobj_dom = NULL; + PyObject *pyobj_dict = NULL; + + virDomainPtr dom; + char *disk = NULL; + char *destxml = NULL; + virTypedParameterPtr params; + int nparams; + unsigned int flags; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *) "OzzOii:virDomainBlockCopy", + &pyobj_dom, &disk, &destxml, &pyobj_dict, &nparams,
... drop nparams here as that is infered from the length of the dict ...
+ &flags)) + return VIR_PY_INT_FAIL; + + if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, NULL, 0) < 0)
and finally overwritten here.
+ return VIR_PY_INT_FAIL; + + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainBlockCopy(dom, disk, destxml, params, nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + return libvirt_intWrap(c_retval); +} + #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */
/************************************************************************ @@ -8286,6 +8318,7 @@ static PyMethodDef libvirtMethods[] = { #if LIBVIR_CHECK_VERSION(1, 2, 8) {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, {(char *) "virDomainListGetStats", libvirt_virDomainListGetStats, METH_VARARGS, NULL}, + {(char *) "virDomainBlockCopy", libvirt_virDomainBlockCopy, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} };
You might be fine if you drop the "nparams" argument from the XML describing the API. You also probably should make the argument optional by passing an empty dict or NONE as a default value (IIRC by using keyword "Optional" in the description) depending on what virPyDictToTypedParams takes as missing typed params. Peter

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- new from v2: - removed parameter nparams - make params optional generator.py | 1 + libvirt-override-api.xml | 9 +++++++++ libvirt-override.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/generator.py b/generator.py index 1daf866..a798274 100755 --- a/generator.py +++ b/generator.py @@ -464,6 +464,7 @@ skip_impl = ( 'virConnectGetCPUModelNames', 'virNodeGetFreePages', 'virNetworkGetDHCPLeases', + 'virDomainBlockCopy', ) lxc_skip_impl = ( diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml index 09bbbf8..51d8273 100644 --- a/libvirt-override-api.xml +++ b/libvirt-override-api.xml @@ -640,5 +640,14 @@ <arg name='flags' type='unsigned int' info='unused, pass 0'/> <return type='char *' info="list of leases"/> </function> + <function name="virDomainBlockCopy" file="python"> + <info>Copy the guest-visible contents of a disk image to a new file described by destxml</info> + <arg name='dom' type='virDomainPtr' info='pointer to domain object'/> + <arg name='disk' type='const char *' info='path to the block device, or device shorthand'/> + <arg name='destxml' type='const char *' info='XML description of the copy destination'/> + <arg name='params' type='virTypedParameterPtr' info='optional pointer to block copy parameter object, or NULL'/> + <arg name='flags' type='unsigned int' info='bitwise-OR of virDomainBlockCopyFlags'/> + <return type='int' info='0 if the operation has started, -1 on failure'/> + </function> </symbols> </api> diff --git a/libvirt-override.c b/libvirt-override.c index 569778d..444a5fe 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -8096,6 +8096,38 @@ libvirt_virDomainListGetStats(PyObject *self ATTRIBUTE_UNUSED, return py_retval; } + +static PyObject * +libvirt_virDomainBlockCopy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) +{ + PyObject *pyobj_dom = NULL; + PyObject *pyobj_dict = NULL; + + virDomainPtr dom; + char *disk = NULL; + char *destxml = NULL; + virTypedParameterPtr params; + int nparams; + unsigned int flags; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *) "Ozz|Oi:virDomainBlockCopy", + &pyobj_dom, &disk, &destxml, &pyobj_dict, &nparams, + &flags)) + return VIR_PY_INT_FAIL; + + if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, NULL, 0) < 0) + return VIR_PY_INT_FAIL; + + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainBlockCopy(dom, disk, destxml, params, nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + return libvirt_intWrap(c_retval); +} + #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ /************************************************************************ @@ -8286,6 +8318,7 @@ static PyMethodDef libvirtMethods[] = { #if LIBVIR_CHECK_VERSION(1, 2, 8) {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, {(char *) "virDomainListGetStats", libvirt_virDomainListGetStats, METH_VARARGS, NULL}, + {(char *) "virDomainBlockCopy", libvirt_virDomainBlockCopy, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} }; -- 1.8.5.5

On 09/02/14 00:08, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
new from v2: - removed parameter nparams - make params optional
generator.py | 1 + libvirt-override-api.xml | 9 +++++++++ libvirt-override.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+)
diff --git a/generator.py b/generator.py index 1daf866..a798274 100755 --- a/generator.py +++ b/generator.py @@ -464,6 +464,7 @@ skip_impl = ( 'virConnectGetCPUModelNames', 'virNodeGetFreePages', 'virNetworkGetDHCPLeases', + 'virDomainBlockCopy', )
lxc_skip_impl = ( diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml index 09bbbf8..51d8273 100644 --- a/libvirt-override-api.xml +++ b/libvirt-override-api.xml @@ -640,5 +640,14 @@ <arg name='flags' type='unsigned int' info='unused, pass 0'/> <return type='char *' info="list of leases"/> </function> + <function name="virDomainBlockCopy" file="python"> + <info>Copy the guest-visible contents of a disk image to a new file described by destxml</info> + <arg name='dom' type='virDomainPtr' info='pointer to domain object'/> + <arg name='disk' type='const char *' info='path to the block device, or device shorthand'/> + <arg name='destxml' type='const char *' info='XML description of the copy destination'/> + <arg name='params' type='virTypedParameterPtr' info='optional pointer to block copy parameter object, or NULL'/> + <arg name='flags' type='unsigned int' info='bitwise-OR of virDomainBlockCopyFlags'/> + <return type='int' info='0 if the operation has started, -1 on failure'/> + </function> </symbols> </api> diff --git a/libvirt-override.c b/libvirt-override.c index 569778d..444a5fe 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -8096,6 +8096,38 @@ libvirt_virDomainListGetStats(PyObject *self ATTRIBUTE_UNUSED, return py_retval; }
+ +static PyObject * +libvirt_virDomainBlockCopy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) +{ + PyObject *pyobj_dom = NULL; + PyObject *pyobj_dict = NULL; + + virDomainPtr dom; + char *disk = NULL; + char *destxml = NULL; + virTypedParameterPtr params; + int nparams; + unsigned int flags; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *) "Ozz|Oi:virDomainBlockCopy", + &pyobj_dom, &disk, &destxml, &pyobj_dict, &nparams, + &flags)) + return VIR_PY_INT_FAIL;
You need to wrap the call below into a if (PyDict_Check(pyobj_dict)) as it doesn't handle "None" gracefully.
+ if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, NULL, 0) < 0) + return VIR_PY_INT_FAIL; + + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainBlockCopy(dom, disk, destxml, params, nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + return libvirt_intWrap(c_retval); +} + #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */
/************************************************************************ @@ -8286,6 +8318,7 @@ static PyMethodDef libvirtMethods[] = { #if LIBVIR_CHECK_VERSION(1, 2, 8) {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, {(char *) "virDomainListGetStats", libvirt_virDomainListGetStats, METH_VARARGS, NULL}, + {(char *) "virDomainBlockCopy", libvirt_virDomainBlockCopy, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} };
ACK with the comment above addressed. Peter

On 09/02/2014 12:17 AM, Peter Krempa wrote:
On 09/02/14 00:08, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
new from v2: - removed parameter nparams - make params optional
generator.py | 1 + libvirt-override-api.xml | 9 +++++++++ libvirt-override.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+)
diff --git a/generator.py b/generator.py index 1daf866..a798274 100755 --- a/generator.py +++ b/generator.py @@ -464,6 +464,7 @@ skip_impl = ( 'virConnectGetCPUModelNames', 'virNodeGetFreePages', 'virNetworkGetDHCPLeases', + 'virDomainBlockCopy', )
lxc_skip_impl = ( diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml index 09bbbf8..51d8273 100644 --- a/libvirt-override-api.xml +++ b/libvirt-override-api.xml @@ -640,5 +640,14 @@ <arg name='flags' type='unsigned int' info='unused, pass 0'/> <return type='char *' info="list of leases"/> </function> + <function name="virDomainBlockCopy" file="python"> + <info>Copy the guest-visible contents of a disk image to a new file described by destxml</info> + <arg name='dom' type='virDomainPtr' info='pointer to domain object'/> + <arg name='disk' type='const char *' info='path to the block device, or device shorthand'/> + <arg name='destxml' type='const char *' info='XML description of the copy destination'/> + <arg name='params' type='virTypedParameterPtr' info='optional pointer to block copy parameter object, or NULL'/> + <arg name='flags' type='unsigned int' info='bitwise-OR of virDomainBlockCopyFlags'/> + <return type='int' info='0 if the operation has started, -1 on failure'/> + </function> </symbols> </api> diff --git a/libvirt-override.c b/libvirt-override.c index 569778d..444a5fe 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -8096,6 +8096,38 @@ libvirt_virDomainListGetStats(PyObject *self ATTRIBUTE_UNUSED, return py_retval; }
+ +static PyObject * +libvirt_virDomainBlockCopy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) +{ + PyObject *pyobj_dom = NULL; + PyObject *pyobj_dict = NULL; + + virDomainPtr dom; + char *disk = NULL; + char *destxml = NULL; + virTypedParameterPtr params; + int nparams; + unsigned int flags; + int c_retval; + + if (!PyArg_ParseTuple(args, (char *) "Ozz|Oi:virDomainBlockCopy", + &pyobj_dom, &disk, &destxml, &pyobj_dict, &nparams, + &flags)) + return VIR_PY_INT_FAIL;
You need to wrap the call below into a if (PyDict_Check(pyobj_dict)) as it doesn't handle "None" gracefully.
+ if (virPyDictToTypedParams(pyobj_dict, ¶ms, &nparams, NULL, 0) < 0) + return VIR_PY_INT_FAIL; + + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainBlockCopy(dom, disk, destxml, params, nparams, flags); + LIBVIRT_END_ALLOW_THREADS; + + return libvirt_intWrap(c_retval); +} + #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */
/************************************************************************ @@ -8286,6 +8318,7 @@ static PyMethodDef libvirtMethods[] = { #if LIBVIR_CHECK_VERSION(1, 2, 8) {(char *) "virConnectGetAllDomainStats", libvirt_virConnectGetAllDomainStats, METH_VARARGS, NULL}, {(char *) "virDomainListGetStats", libvirt_virDomainListGetStats, METH_VARARGS, NULL}, + {(char *) "virDomainBlockCopy", libvirt_virDomainBlockCopy, METH_VARARGS, NULL}, #endif /* LIBVIR_CHECK_VERSION(1, 2, 8) */ {NULL, NULL, 0, NULL} };
ACK with the comment above addressed.
Peter
Thanks for review, pushed whole series. Pavel
participants (2)
-
Pavel Hrdina
-
Peter Krempa