[libvirt] [python PATCHv2] Implement new virNetworkGetDHCPLeases API

Peter Krempa pkrempa at redhat.com
Fri Jun 27 08:42:33 UTC 2014


From: Nehal J Wani <nehaljw.kkd1 at gmail.com>

This API returns a list of DHCP leases for all network interfaces
connected to the given virtual network or limited output just for one
interface if mac is specified.

Example Output:
[{'iface': 'virbr3', 'ipaddr': '192.168.150.181', 'hostname': 'ubuntu14',
    'expirytime': 1403737495L, 'prefix': 24, 'clientid': None,
    'mac': '52:54:00:e8:73:eb', 'iaid': None, 'type': 0},
 {'iface': 'virbr3', 'ipaddr': '2001:db8:ca2:2:1::bd', 'hostname': 'fedora20-test',
    'expirytime': 1403738587L, 'prefix': 64, 'clientid': '00:04:b1:d8:86:42:e1:6a:aa:cf:d5:86:94:23:6f:94:04:cd',
    'mac': '52:54:00:5b:40:98', 'iaid': '5980312', 'type': 1}]

Signed-off-by: Peter Krempa <pkrempa at redhat.com>
---
 examples/README          |  1 +
 examples/dhcpleases.py   | 53 +++++++++++++++++++++++++++++
 generator.py             |  4 +++
 libvirt-override-api.xml |  7 ++++
 libvirt-override.c       | 88 ++++++++++++++++++++++++++++++++++++++++++++++++
 sanitytest.py            |  6 ++++
 6 files changed, 159 insertions(+)
 create mode 100755 examples/dhcpleases.py

diff --git a/examples/README b/examples/README
index f4db76c..5b5d405 100644
--- a/examples/README
+++ b/examples/README
@@ -10,6 +10,7 @@ domsave.py  - save all running domU's into a directory
 domrestore.py - restore domU's from their saved files in a directory
 esxlist.py  - list active domains of an VMware ESX host and print some info.
               also demonstrates how to use the libvirt.openAuth() method
+dhcpleases.py - list dhcp leases for a given virtual network

 The XML files in this directory are examples of the XML format that libvirt
 expects, and will have to be adapted for your setup. They are only needed
diff --git a/examples/dhcpleases.py b/examples/dhcpleases.py
new file mode 100755
index 0000000..c172dc2
--- /dev/null
+++ b/examples/dhcpleases.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+# netdhcpleases - print leases info for given virtual network
+
+import libvirt
+import sys
+import time
+
+def usage():
+    print "Usage: %s [URI] NETWORK" % sys.argv[0]
+    print "        Print leases info for a given virtual network"
+
+uri = None
+network = None
+args = len(sys.argv)
+
+if args == 2:
+    network = sys.argv[1]
+elif args == 3:
+    uri = sys.argv[1]
+    network = sys.argv[2]
+else:
+    usage()
+    sys.exit(2)
+
+conn = libvirt.open(uri)
+if conn == None:
+    print "Unable to open connection to libvirt"
+    sys.exit(1)
+
+try:
+    net = conn.networkLookupByName(network)
+except libvirt.libvirtError:
+    print "Network %s not found" % network
+    sys.exit(0)
+
+leases = net.DHCPLeases();
+if (leases == None):
+    print "Failed to get leases for %s" % net.name()
+    sys.exit(0)
+
+def toIPAddrType(addrType):
+    if addrType == libvirt.VIR_IP_ADDR_TYPE_IPV4:
+        return "ipv4"
+    elif addrType == libvirt.VIR_IP_ADDR_TYPE_IPV6:
+        return "ipv6"
+
+print " {0:20} {1:18} {2:9} {3:25} {4:15} {5}".format("Expiry Time", "MAC address", "Protocol", "IP address", "Hostname", "Client ID or DUID")
+print "-"*115
+
+for lease in leases:
+    print " {0:20}".format(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(lease['expirytime']))),
+    print "{0:18} {1:9}".format(lease['mac'], toIPAddrType(lease['type'])),
+    print "{0:<25} {1:15} {2}".format("{}/{}".format(lease['ipaddr'], lease['prefix']), lease['hostname'], lease['clientid'])
diff --git a/generator.py b/generator.py
index 03027c6..a12c52b 100755
--- a/generator.py
+++ b/generator.py
@@ -463,6 +463,7 @@ skip_impl = (
     'virDomainMigrateToURI3',
     'virConnectGetCPUModelNames',
     'virNodeGetFreePages',
+    'virNetworkGetDHCPLeases',
 )

 lxc_skip_impl = (
@@ -568,6 +569,8 @@ skip_function = (
     "virTypedParamsGetString",
     "virTypedParamsGetUInt",
     "virTypedParamsGetULLong",
+
+    'virNetworkDHCPLeaseFree', # only useful in C, python code uses list
 )

 lxc_skip_function = (
@@ -1115,6 +1118,7 @@ def nameFixup(name, classe, type, file):
     elif name[0:13] == "virNetworkGet":
         func = name[13:]
         func = func[0:1].lower() + func[1:]
+        func = func.replace("dHCP", "DHCP")
     elif name[0:10] == "virNetwork":
         func = name[10:]
         func = func[0:1].lower() + func[1:]
diff --git a/libvirt-override-api.xml b/libvirt-override-api.xml
index bbf0ab1..09bbbf8 100644
--- a/libvirt-override-api.xml
+++ b/libvirt-override-api.xml
@@ -633,5 +633,12 @@
       <arg name='flags' type='int' info='unused, pass 0'/>
       <return type='char *' info='the list available memory in the cells'/>
     </function>
+    <function name="virNetworkGetDHCPLeases" file='python'>
+      <info>Returns a list of dhcp leases for interfaces connected to the given virtual network</info>
+      <arg name='network' type='virNetworkPtr' info='a network object'/>
+      <arg name='mac' type='const char *' info='optional mac address'/>
+      <arg name='flags' type='unsigned int' info='unused, pass 0'/>
+      <return type='char *' info="list of leases"/>
+    </function>
   </symbols>
 </api>
diff --git a/libvirt-override.c b/libvirt-override.c
index 40aefcc..ed5e9e4 100644
--- a/libvirt-override.c
+++ b/libvirt-override.c
@@ -7866,6 +7866,93 @@ libvirt_virNodeGetFreePages(PyObject *self ATTRIBUTE_UNUSED,
     VIR_FREE(counts);
     return py_retval;
 }
+
+
+static PyObject *
+libvirt_virNetworkGetDHCPLeases(PyObject *self ATTRIBUTE_UNUSED,
+                                PyObject *args)
+{
+    PyObject *py_retval = NULL;
+    PyObject *py_lease = NULL;
+    virNetworkPtr network;
+    PyObject *pyobj_network;
+    unsigned int flags;
+    virNetworkDHCPLeasePtr *leases = NULL;
+    int leases_count;
+    char *mac = NULL;
+    size_t i;
+
+    if (!PyArg_ParseTuple(args, (char *) "Ozi:virNetworkDHCPLeasePtr",
+                          &pyobj_network, &mac, &flags))
+        return NULL;
+
+    network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network);
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    leases_count = virNetworkGetDHCPLeases(network, mac, &leases, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (leases_count < 0) {
+        py_retval = VIR_PY_NONE;
+        goto cleanup;
+    }
+
+    if (!(py_retval = PyList_New(leases_count)))
+        goto no_memory;
+
+    for (i = 0; i < leases_count; i++) {
+        virNetworkDHCPLeasePtr lease = leases[i];
+
+        if ((py_lease = PyDict_New()) == NULL)
+            goto no_memory;
+
+#define VIR_SET_LEASE_ITEM(NAME, VALUE_OBJ_FUNC)                            \
+        do {                                                                \
+            PyObject *tmp_val;                                              \
+                                                                            \
+            if (!(tmp_val = VALUE_OBJ_FUNC))                                \
+                goto no_memory;                                             \
+                                                                            \
+            if (PyDict_SetItemString(py_lease, NAME, tmp_val) < 0) {        \
+                Py_DECREF(tmp_val);                                         \
+                goto no_memory;                                             \
+            }                                                               \
+        } while (0)
+
+        VIR_SET_LEASE_ITEM("iface", libvirt_charPtrWrap(lease->iface));
+        VIR_SET_LEASE_ITEM("expirytime", libvirt_longlongWrap(lease->expirytime));
+        VIR_SET_LEASE_ITEM("type", libvirt_intWrap(lease->type));
+        VIR_SET_LEASE_ITEM("mac", libvirt_charPtrWrap(lease->mac));
+        VIR_SET_LEASE_ITEM("ipaddr", libvirt_charPtrWrap(lease->ipaddr));
+        VIR_SET_LEASE_ITEM("prefix", libvirt_uintWrap(lease->prefix));
+        VIR_SET_LEASE_ITEM("hostname", libvirt_charPtrWrap(lease->hostname));
+        VIR_SET_LEASE_ITEM("clientid", libvirt_charPtrWrap(lease->clientid));
+        VIR_SET_LEASE_ITEM("iaid", libvirt_charPtrWrap(lease->iaid));
+
+#undef VIR_SET_LEASE_ITEM
+
+        if (PyList_SetItem(py_retval, i, py_lease) < 0)
+            goto no_memory;
+
+        py_lease = NULL;
+    }
+
+ cleanup:
+    Py_XDECREF(py_lease);
+    if (leases) {
+        for (i = 0; i < leases_count; i++)
+            virNetworkDHCPLeaseFree(leases[i]);
+    }
+    VIR_FREE(leases);
+
+    return py_retval;
+
+ no_memory:
+    Py_XDECREF(py_retval);
+    py_retval = PyErr_NoMemory();
+    goto cleanup;
+}
+
 #endif /* LIBVIR_CHECK_VERSION(1, 2, 6) */

 /************************************************************************
@@ -8051,6 +8138,7 @@ static PyMethodDef libvirtMethods[] = {
 #endif /* LIBVIR_CHECK_VERSION(1, 2, 5) */
 #if LIBVIR_CHECK_VERSION(1, 2, 6)
     {(char *) "virNodeGetFreePages", libvirt_virNodeGetFreePages, METH_VARARGS, NULL},
+    {(char *) "virNetworkGetDHCPLeases", libvirt_virNetworkGetDHCPLeases, METH_VARARGS, NULL},
 #endif /* LIBVIR_CHECK_VERSION(1, 2, 6) */
     {NULL, NULL, 0, NULL}
 };
diff --git a/sanitytest.py b/sanitytest.py
index 6067a3f..4f4a648 100644
--- a/sanitytest.py
+++ b/sanitytest.py
@@ -78,6 +78,9 @@ for cname in wantfunctions:
     if name[0:14] == "virTypedParams":
         continue

+    if name[0:23] == "virNetworkDHCPLeaseFree":
+        continue
+
     # These aren't functions, they're callback signatures
     if name in ["virConnectAuthCallbackPtr", "virConnectCloseFunc",
                 "virStreamSinkFunc", "virStreamSourceFunc", "virStreamEventCallback",
@@ -210,6 +213,9 @@ for name in sorted(basicklassmap):
     if func[0:8] == "fSFreeze" or func[0:6] == "fSThaw":
         func = "fs" + func[2:]

+    if klass == "virNetwork":
+        func = func.replace("dHCP", "DHCP")
+
     # ...except when they don't. More stupid naming
     # decisions we can't fix
     if func == "iD":
-- 
1.9.3




More information about the libvir-list mailing list