[libvirt] [PATCH python] Add missing binding of security model/label APIs

From: "Daniel P. Berrange" <berrange@redhat.com> The virNodeGetSecurityModel, virDomainGetSecurityLabel and virDomainGetSecurityLabelList methods were disabled in the python binding for inexplicable reasons. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- generator.py | 6 ++-- libvirt-override-api.xml | 15 +++++++++ libvirt-override.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ typewrappers.c | 9 ++++++ typewrappers.h | 1 + 5 files changed, 110 insertions(+), 3 deletions(-) diff --git a/generator.py b/generator.py index ab2a97f..273efbd 100755 --- a/generator.py +++ b/generator.py @@ -381,6 +381,9 @@ skip_impl = ( 'virDomainGetJobInfo', 'virDomainGetJobStats', 'virNodeGetInfo', + 'virNodeGetSecurityModel', + 'virDomainGetSecurityLabel', + 'virDomainGetSecurityLabelList', 'virDomainGetUUID', 'virDomainGetUUIDString', 'virDomainLookupByUUID', @@ -476,9 +479,6 @@ skip_function = ( 'virCopyLastError', # Python API is called virGetLastError instead 'virConnectOpenAuth', # Python C code is manually written 'virDefaultErrorFunc', # Python virErrorFuncHandler impl calls this from C - 'virDomainGetSecurityLabel', # Needs investigation... - 'virDomainGetSecurityLabelList', # Needs investigation... - 'virNodeGetSecurityModel', # Needs investigation... 'virConnectDomainEventRegister', # overridden in virConnect.py 'virConnectDomainEventDeregister', # overridden in virConnect.py 'virConnectDomainEventRegisterAny', # overridden in virConnect.py diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml index 337d0a0..d5b25b5 100644 --- a/libvirt-override-api.xml +++ b/libvirt-override-api.xml @@ -104,6 +104,21 @@ <return type='char *' info='the list of information or None in case of error'/> <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> </function> + <function name='virNodeGetSecurityModel' file='python'> + <info>Extract information about the host security model</info> + <return type='char *' info='the list of information or None in case of error'/> + <arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> + </function> + <function name='virDomainGetSecurityLabel' file='python'> + <info>Extract information about the domain security label. Only the first label will be returned.</info> + <return type='char *' info='the list of information or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='a domain object'/> + </function> + <function name='virDomainGetSecurityLabelList' file='python'> + <info>Extract information about the domain security label. A list of all labels will be returned.</info> + <return type='char *' info='the list of information or None in case of error'/> + <arg name='domain' type='virDomainPtr' info='a domain object'/> + </function> <function name='virNodeGetCPUStats' file='python'> <info>Extract node's CPU statistics.</info> <return type='char *' info='dictionary mapping field names to values or None in case of error'/> diff --git a/libvirt-override.c b/libvirt-override.c index d3802de..42e253e 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -2865,6 +2865,83 @@ libvirt_virNodeGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { } static PyObject * +libvirt_virNodeGetSecurityModel(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virConnectPtr conn; + PyObject *pyobj_conn; + virSecurityModel model; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetSecurityModel", &pyobj_conn)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virNodeGetSecurityModel(conn, &model); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(2); + PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(&model.model[0])); + PyList_SetItem(py_retval, 1, libvirt_constcharPtrWrap(&model.doi[0])); + return py_retval; +} + +static PyObject * +libvirt_virDomainGetSecurityLabel(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr dom; + PyObject *pyobj_dom; + virSecurityLabel label; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetSecurityLabel", &pyobj_dom)) + return NULL; + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainGetSecurityLabel(dom, &label); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(2); + PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(&label.label[0])); + PyList_SetItem(py_retval, 1, libvirt_boolWrap(label.enforcing)); + return py_retval; +} + +#if LIBVIR_CHECK_VERSION(0, 9, 13) +static PyObject * +libvirt_virDomainGetSecurityLabelList(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; + virDomainPtr dom; + PyObject *pyobj_dom; + virSecurityLabel *labels; + size_t i; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetSecurityLabel", &pyobj_dom)) + return NULL; + dom = (virDomainPtr) PyvirDomain_Get(pyobj_dom); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virDomainGetSecurityLabelList(dom, &labels); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(0); + for (i = 0 ; i < c_retval ; i++) { + PyObject *entry = PyList_New(2); + PyList_SetItem(entry, 0, libvirt_constcharPtrWrap(&labels[i].label[0])); + PyList_SetItem(entry, 1, libvirt_boolWrap(labels[i].enforcing)); + PyList_Append(py_retval, entry); + } + free(labels); + return py_retval; +} +#endif + +static PyObject * libvirt_virDomainGetUUID(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { PyObject *py_retval; unsigned char uuid[VIR_UUID_BUFLEN]; @@ -7304,6 +7381,11 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainGetControlInfo", libvirt_virDomainGetControlInfo, METH_VARARGS, NULL}, {(char *) "virDomainGetBlockInfo", libvirt_virDomainGetBlockInfo, METH_VARARGS, NULL}, {(char *) "virNodeGetInfo", libvirt_virNodeGetInfo, METH_VARARGS, NULL}, + {(char *) "virNodeGetSecurityModel", libvirt_virNodeGetSecurityModel, METH_VARARGS, NULL}, + {(char *) "virDomainGetSecurityLabel", libvirt_virDomainGetSecurityLabel, METH_VARARGS, NULL}, +#if LIBVIR_CHECK_VERSION(0, 9, 13) + {(char *) "virDomainGetSecurityLabelList", libvirt_virDomainGetSecurityLabelList, METH_VARARGS, NULL}, +#endif /* LIBVIR_CHECK_VERSION(0, 9, 13) */ {(char *) "virNodeGetCPUStats", libvirt_virNodeGetCPUStats, METH_VARARGS, NULL}, {(char *) "virNodeGetMemoryStats", libvirt_virNodeGetMemoryStats, METH_VARARGS, NULL}, {(char *) "virDomainGetUUID", libvirt_virDomainGetUUID, METH_VARARGS, NULL}, diff --git a/typewrappers.c b/typewrappers.c index d6cbbf1..1622986 100644 --- a/typewrappers.c +++ b/typewrappers.c @@ -116,6 +116,15 @@ libvirt_constcharPtrWrap(const char *str) return ret; } +PyObject * +libvirt_boolWrap(int val) +{ + if (val) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + int libvirt_intUnwrap(PyObject *obj, int *val) { diff --git a/typewrappers.h b/typewrappers.h index d871d3f..04e364f 100644 --- a/typewrappers.h +++ b/typewrappers.h @@ -164,6 +164,7 @@ PyObject * libvirt_ulonglongWrap(unsigned long long val); PyObject * libvirt_charPtrWrap(char *str); PyObject * libvirt_charPtrSizeWrap(char *str, Py_ssize_t size); PyObject * libvirt_constcharPtrWrap(const char *str); +PyObject * libvirt_boolWrap(int val); int libvirt_intUnwrap(PyObject *obj, int *val); int libvirt_uintUnwrap(PyObject *obj, unsigned int *val); int libvirt_longUnwrap(PyObject *obj, long *val); -- 1.8.3.1

On 11/26/2013 11:32 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
The virNodeGetSecurityModel, virDomainGetSecurityLabel and virDomainGetSecurityLabelList methods were disabled in the python binding for inexplicable reasons.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> ---
+++ b/libvirt-override.c @@ -2865,6 +2865,83 @@ libvirt_virNodeGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { }
static PyObject * +libvirt_virNodeGetSecurityModel(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
{ on its own line (Hmm, we aren't very consistent in this file)
+ PyObject *py_retval; + int c_retval; + virConnectPtr conn; + PyObject *pyobj_conn; + virSecurityModel model; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetSecurityModel", &pyobj_conn)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virNodeGetSecurityModel(conn, &model); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(2);
If PyList_New() fails, py_retval is NULL,...
+ PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(&model.model[0]));
...and this will crash. Instead, you should just return NULL early. (Then again, we have LOTS of places where we aren't checking the return of PyList_SetItem for failure, which is a major cleanup in its own right).
+ PyList_SetItem(py_retval, 1, libvirt_constcharPtrWrap(&model.doi[0])); + return py_retval; +} + +static PyObject * +libvirt_virDomainGetSecurityLabel(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
{ placement
+ py_retval = PyList_New(2); + PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(&label.label[0]));
Same comment on error handling.
+ PyList_SetItem(py_retval, 1, libvirt_boolWrap(label.enforcing)); + return py_retval; +} + +#if LIBVIR_CHECK_VERSION(0, 9, 13) +static PyObject * +libvirt_virDomainGetSecurityLabelList(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
{ placement
+ py_retval = PyList_New(0); + for (i = 0 ; i < c_retval ; i++) {
No space before semicolon (hmm, we lost our syntax checker in the split)
+ PyObject *entry = PyList_New(2); + PyList_SetItem(entry, 0, libvirt_constcharPtrWrap(&labels[i].label[0]));
Again, can't libvirt_constcharPtrWrap() return NULL (on OOM situations), which will crash PyList_SetItem()? Only findings are style-related or part of a bigger cleanup needed for proper error handling, so ACK. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Tue, Nov 26, 2013 at 01:17:16PM -0700, Eric Blake wrote:
On 11/26/2013 11:32 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
The virNodeGetSecurityModel, virDomainGetSecurityLabel and virDomainGetSecurityLabelList methods were disabled in the python binding for inexplicable reasons.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> ---
+++ b/libvirt-override.c @@ -2865,6 +2865,83 @@ libvirt_virNodeGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { }
static PyObject * +libvirt_virNodeGetSecurityModel(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
{ on its own line (Hmm, we aren't very consistent in this file)
+ PyObject *py_retval; + int c_retval; + virConnectPtr conn; + PyObject *pyobj_conn; + virSecurityModel model; + + if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetSecurityModel", &pyobj_conn)) + return NULL; + conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn); + + LIBVIRT_BEGIN_ALLOW_THREADS; + c_retval = virNodeGetSecurityModel(conn, &model); + LIBVIRT_END_ALLOW_THREADS; + if (c_retval < 0) + return VIR_PY_NONE; + py_retval = PyList_New(2);
If PyList_New() fails, py_retval is NULL,...
+ PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(&model.model[0]));
...and this will crash. Instead, you should just return NULL early. (Then again, we have LOTS of places where we aren't checking the return of PyList_SetItem for failure, which is a major cleanup in its own right).
+ PyList_SetItem(py_retval, 1, libvirt_constcharPtrWrap(&model.doi[0])); + return py_retval; +} + +static PyObject * +libvirt_virDomainGetSecurityLabel(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
{ placement
+ py_retval = PyList_New(2); + PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(&label.label[0]));
Same comment on error handling.
+ PyList_SetItem(py_retval, 1, libvirt_boolWrap(label.enforcing)); + return py_retval; +} + +#if LIBVIR_CHECK_VERSION(0, 9, 13) +static PyObject * +libvirt_virDomainGetSecurityLabelList(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
{ placement
+ py_retval = PyList_New(0); + for (i = 0 ; i < c_retval ; i++) {
No space before semicolon (hmm, we lost our syntax checker in the split)
Yeah, I've tried to get maint.mk / cfg.mk working with a trivial GNUmakefile, but it seems they rely on a number of make variables set by configure which we obviously don't have available. So I failed in this attempt. Perhaps you'll have more luck with better understanding of GNULIB
+ PyObject *entry = PyList_New(2); + PyList_SetItem(entry, 0, libvirt_constcharPtrWrap(&labels[i].label[0]));
Again, can't libvirt_constcharPtrWrap() return NULL (on OOM situations), which will crash PyList_SetItem()?
Only findings are style-related or part of a bigger cleanup needed for proper error handling, so ACK.
Yeah, the python binding is pretty awful at this - we need a major cleanup to make the binding OOM-safe. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Eric Blake