Enable python bindings for hello

This is the eighth and final post in the series “HOWTO: Add libvirt support for a qemu command”

One more to go. This time we will enable our command in the libvirt python bindings. These bindings are auto-generated but (due to the virHelloParams structure, we must hand code an implementation. While not that much code, this part can be tricky because the API generator doesn’t seem to be documented. Also, you will need to learn how to work with python objects in C.

diff --git a/python/generator.py b/python/generator.py
index 569f4a8..5b830bc 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -166,7 +166,6 @@ def enum(type, name, value):
 functions_failed = []
 functions_skipped = [
-    "virDomainHello",
 skipped_modules = {
@@ -181,7 +180,6 @@ skipped_types = {
      'virConnectDomainEventIOErrorCallback': "No function types in python",
      'virConnectDomainEventGraphicsCallback': "No function types in python",
      'virEventAddHandleFunc': "No function types in python",
-     'virHelloParamsPtr': "Not implemented yet",

First, undo the compile fixes we made at the start of this patch series. Removing these lines tells the generator not to skip our function anymore.

@@ -257,6 +255,7 @@ py_types = {
     'const virDomainSnapshotPtr':  ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
     'virDomainSnapshot *':  ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
     'const virDomainSnapshot *':  ('O', "virDomainSnapshot", "virDomainSnapshotPtr", "virDomainSnapshotPtr"),
+    'virHelloParamsPtr': ('O', "virHelloParams", "virHelloParamsPtr", "virHelloParamsPtr"),
 py_return_types = {

Tell the generator about the virHelloParamsPtr argument type. We will treat this C structure as a python object (actually a dictionary — read on).

@@ -343,6 +342,7 @@ skip_impl = (
+    'virDomainHello',

This tells the generator that we will supply a hand-coded implementation of virDomainHello.

diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index 54deeb5..4d1ea7d 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -308,5 +308,11 @@
       <arg name='flags' type='unsigned int' info='flags, curently unused'/>
       <return type='int' info="0 on success, -1 on error"/>
+    <function name='virDomainHello' file='python'>
+      <info>Say hallo to a domain</info>
+      <arg name='domain' type='virDomainPtr' info='pointer to the domain'/>
+      <arg name='params' type='virHelloParamsPtr' info='A dictionary of parameters' />
+      <return type='str *' info='A Greeting from the domain' />
+    </function>

Manually document the API

diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 4a9b432..20df116 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -2350,6 +2350,42 @@ libvirt_virDomainGetJobInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+static PyObject *
+libvirt_virDomainHello(PyObject *self ATTRIBUTE_UNUSED,
+                       PyObject *args) {
+    virDomainPtr domain;
+    struct _virHelloParams params;
+    PyObject *pyobj_domain, *pyobj_params, *pyobj;
+    char *c_retval;
+    PyObject *ret;
+    if (!PyArg_ParseTuple(args, (char *)"OO:virDomainHello",
+                          &pyobj_domain, &pyobj_params))
+        return(NULL);
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+    pyobj = PyDict_GetItemString(pyobj_params, "exclaim");
+    if (!pyobj)
+        params.exclaim = 0;
+    else
+        params.exclaim = (int) PyInt_AS_LONG(pyobj);
+    pyobj = PyDict_GetItemString(pyobj_params, "lang");
+    if (!pyobj)
+        params.lang = NULL;
+    else
+        params.lang = PyString_AsString(pyobj);
+    c_retval = virDomainHello(domain, &params);
+    if (c_retval == NULL)
+        return VIR_PY_NONE;
+    ret = PyString_FromString(c_retval);
+    free(c_retval);
+    return ret;
  * Helper functions to avoid importing modules
@@ -3585,6 +3621,7 @@ static PyMethodDef libvirtMethods[] = {
     {(char *) "virDomainGetJobInfo", libvirt_virDomainGetJobInfo, METH_VARARGS, NULL},
     {(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
     {(char *) "virDomainRevertToSnapshot", libvirt_virDomainRevertToSnapshot, METH_VARARGS, NULL},
+    {(char *) "virDomainHello", libvirt_virDomainHello, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}

Here lies the meat of today’s exercise. Above we supply a python-to-c wrapper function. According to our oft-repeated formula we: unpack arguments, make the C API call, and package the return value. The python representation of virHelloParams is a dictionary containing the keys lang and exclaim. Both keys are optional. If supplied, lang is a string and exclaim is a boolean.

Well that’s it! You’re done with “Hello World” for libvirt. Thanks for following my tutorial. I welcome your comments on anything (the tutorial itself but especially the process for adding new functionality to libvirt). If my opinion hasn’t come through in the tutorial, I think there is room for simplification 🙂

About aglitke

I am a software engineer working on Linux, open source software, and virtualization. I am proud to work at Red Hat on oVirt and Red Hat Virtualization with a focus on software defined storage. Other notable projects I have been involved in include: The Linux ppc64 architecture, Linux kernel crash dumps (kdump), Linux huge pages and libhugetlbfs, qemu, libvirt, and the Memory Overcommitment Manager.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s