[libvirt] [python PATCH] Implement new virNetworkGetDHCPLeases{ForMAC} APIs

Nehal J Wani nehaljw.kkd1 at gmail.com
Wed Jun 25 22:45:30 UTC 2014


These APIs return 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}]

---
 examples/README          |   1 +
 examples/dhcpleases.py   |  53 +++++++++++++++
 generator.py             |   5 ++
 libvirt-override-api.xml |  14 ++++
 libvirt-override.c       | 166 +++++++++++++++++++++++++++++++++++++++++++++++
 sanitytest.py            |   6 ++
 6 files changed, 245 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..a053022 100755
--- a/generator.py
+++ b/generator.py
@@ -463,6 +463,8 @@ skip_impl = (
     'virDomainMigrateToURI3',
     'virConnectGetCPUModelNames',
     'virNodeGetFreePages',
+    'virNetworkGetDHCPLeases',
+    'virNetworkGetDHCPLeasesForMAC',
 )
 
 lxc_skip_impl = (
@@ -568,6 +570,8 @@ skip_function = (
     "virTypedParamsGetString",
     "virTypedParamsGetUInt",
     "virTypedParamsGetULLong",
+
+    'virNetworkDHCPLeaseFree', # only useful in C, python code uses list
 )
 
 lxc_skip_function = (
@@ -1115,6 +1119,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..a1d7c03 100644
--- a/libvirt-override-api.xml
+++ b/libvirt-override-api.xml
@@ -633,5 +633,19 @@
       <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='flags' type='unsigned int' info='unused, pass 0'/>
+      <return type='char *' info="list of leases"/>
+    </function>
+    <function name="virNetworkGetDHCPLeasesForMAC" file='python'>
+      <info>Returns a list of dhcp leases for a particular interface
+            (specified by mac) connected to the given virtual network</info>
+      <arg name='network' type='virNetworkPtr' info='a network object'/>
+      <arg name='mac' type='const char *' info='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..b345b21 100644
--- a/libvirt-override.c
+++ b/libvirt-override.c
@@ -7866,6 +7866,170 @@ 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 = VIR_PY_NONE;
+    virNetworkPtr network;
+    PyObject *pyobj_network;
+    unsigned int flags;
+    virNetworkDHCPLeasePtr *leases = NULL;
+    int leases_count = 0;
+    size_t i;
+    int ret;
+
+    bool full_free = true;
+
+    if (!PyArg_ParseTuple(args, (char *) "Oi:virNetworkDHCPLeasePtr",
+                          &pyobj_network, &flags))
+        return NULL;
+
+    network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network);
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    leases_count = virNetworkGetDHCPLeases(network, &leases, flags);
+    ret = leases_count;
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (ret < 0)
+        goto cleanup;
+
+    if (!(py_retval = PyList_New(leases_count)))
+        goto no_memory;
+
+    for (i = 0; i < leases_count; i++) {
+        virNetworkDHCPLeasePtr lease = leases[i];
+        PyObject *py_lease = NULL;
+
+        if ((py_lease = PyDict_New()) == NULL)
+            goto no_memory;
+
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("iface"),
+                       libvirt_charPtrWrap(lease->iface));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("expirytime"),
+                       libvirt_longlongWrap(lease->expirytime));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("type"),
+                       libvirt_intWrap(lease->type));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("mac"),
+                       libvirt_charPtrWrap(lease->mac));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("ipaddr"),
+                       libvirt_charPtrWrap(lease->ipaddr));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("prefix"),
+                       libvirt_uintWrap(lease->prefix));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("hostname"),
+                       libvirt_charPtrWrap(lease->hostname));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("clientid"),
+                       libvirt_charPtrWrap(lease->clientid));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("iaid"),
+                       libvirt_charPtrWrap(lease->iaid));
+
+        PyList_SetItem(py_retval, i, py_lease);
+    }
+
+    full_free = false;
+
+ cleanup:
+    if (leases) {
+        for (i = 0; full_free && 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;
+}
+
+static PyObject *
+libvirt_virNetworkGetDHCPLeasesForMAC(PyObject *self ATTRIBUTE_UNUSED,
+                                      PyObject *args)
+{
+    PyObject *py_retval = VIR_PY_NONE;
+    virNetworkPtr network;
+    PyObject *pyobj_network;
+    PyObject *pyobj_mac;
+    unsigned int flags;
+    virNetworkDHCPLeasePtr *leases = NULL;
+    int leases_count = 0;
+    char *mac = NULL;
+    size_t i;
+    int ret;
+
+    bool full_free = true;
+
+    if (!PyArg_ParseTuple(args, (char *) "OOi:virNetworkDHCPLeasePtr",
+                          &pyobj_network, &pyobj_mac, &flags))
+        return NULL;
+
+    libvirt_charPtrUnwrap(pyobj_mac, &mac);
+
+    network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network);
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    leases_count = virNetworkGetDHCPLeasesForMAC(network, mac, &leases, flags);
+    ret = leases_count;
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (ret < 0)
+        goto cleanup;
+
+    if (!(py_retval = PyList_New(leases_count)))
+        goto no_memory;
+
+    for (i = 0; i < leases_count; i++) {
+        virNetworkDHCPLeasePtr lease = leases[i];
+        PyObject *py_lease = NULL;
+
+        if (!STREQ(mac, lease->mac))
+            continue;
+
+        if ((py_lease = PyDict_New()) == NULL)
+            goto no_memory;
+
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("iface"),
+                       libvirt_charPtrWrap(lease->iface));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("expirytime"),
+                       libvirt_longlongWrap(lease->expirytime));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("type"),
+                       libvirt_intWrap(lease->type));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("mac"),
+                       libvirt_charPtrWrap(lease->mac));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("ipaddr"),
+                       libvirt_charPtrWrap(lease->ipaddr));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("prefix"),
+                       libvirt_uintWrap(lease->prefix));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("hostname"),
+                       libvirt_charPtrWrap(lease->hostname));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("clientid"),
+                       libvirt_charPtrWrap(lease->clientid));
+        PyDict_SetItem(py_lease, libvirt_charPtrWrap("iaid"),
+                       libvirt_charPtrWrap(lease->iaid));
+
+        PyList_SetItem(py_retval, i, py_lease);
+    }
+
+    full_free = false;
+
+ cleanup:
+    if (leases) {
+        for (i = 0; full_free && 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 +8215,8 @@ 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},
+    {(char *) "virNetworkGetDHCPLeasesForMAC", libvirt_virNetworkGetDHCPLeasesForMAC, 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