Following on from this thread: https://www.redhat.com/archives/libvir-list/2007-March/thread.html#00341The first attachment is a patch which changes the generated Python bindings so that they always raise an exception when an underlying error occurs in the C libvirt library.
The second attachment is for information only (not to be applied) - it shows the differences in the generated file libvirtclass.py. I have checked each of these changes by hand against both the libvirt.c interface description and the C implementation of the Python bindings (libvir.c and libvirt-py.c), and each change seems correct.
I have _not_ tested this against virt-manager. It is quite possible that virt-manager will cease to work if it wasn't checking the return values from affected functions carefully. I'll check this later today and supply a patch (to virt-manager) if necessary.
I have some additional questions about the Python bindings, but I'll put those in a separate thread.
Rich. -- Emerging Technologies, Red Hat http://et.redhat.com/~rjones/ 64 Baker Street, London, W1U 7DF Mobile: +44 7866 314 421 "[Negative numbers] darken the very whole doctrines of the equations and make dark of the things which are in their nature excessively obvious and simple" (Francis Maseres FRS, mathematician, 1759)
Index: python/generator.py
===================================================================
RCS file: /data/cvs/libvirt/python/generator.py,v
retrieving revision 1.18
diff -u -r1.18 generator.py
--- python/generator.py 16 Mar 2007 10:44:44 -0000 1.18
+++ python/generator.py 27 Mar 2007 11:42:09 -0000
@@ -9,6 +9,7 @@
import os
import sys
import string
+import re
if __name__ == "__main__":
# launched as a script
@@ -575,6 +576,25 @@
'virNetworkDestroy': "self._o = None",
}
+# Functions returning an integral type which need special rules to
+# check for errors and raise exceptions.
+functions_int_exception_test = {
+ 'virDomainGetMaxMemory': "%s == 0",
+}
+functions_int_default_test = "%s == -1"
+
+def is_integral_type (name):
+ return not re.search ("^(unsigned)? ?(int|long)$", name) is None
+
+# Functions returning lists which need special rules to check for errors
+# and raise exceptions.
+functions_list_exception_test = {
+}
+functions_list_default_test = "%s is None"
+
+def is_list_type (name):
+ return name[-1:] == "*"
+
def nameFixup(name, classe, type, file):
# avoid a desastrous clash
listname = classe + "List"
@@ -782,7 +802,8 @@
classes.write("__o");
n = n + 1
classes.write(")\n");
- if ret[0] != "void":
+
+ if ret[0] != "void":
if classes_type.has_key(ret[0]):
#
# Raise an exception
@@ -797,8 +818,33 @@
classes.write(" return ");
classes.write(classes_type[ret[0]][1] % ("ret"));
classes.write("\n");
+
+ # For functions returning an integral type there are
+ # several things that we can do, depending on the
+ # contents of functions_int_*:
+ elif is_integral_type (ret[0]):
+ if functions_int_exception_test.has_key (name):
+ test = functions_int_exception_test[name]
+ else:
+ test = functions_int_default_test
+ classes.write ((" if " + test +
+ ": raise libvirtError ('%s() failed')\n") %
+ ("ret", name))
+ classes.write(" return ret\n")
+
+ elif is_list_type (ret[0]):
+ if functions_list_exception_test.has_key (name):
+ test = functions_list_exception_test[name]
+ else:
+ test = functions_list_default_test
+ classes.write ((" if " + test +
+ ": raise libvirtError ('%s() failed')\n") %
+ ("ret", name))
+ classes.write(" return ret\n")
+
else:
- classes.write(" return ret\n");
+ classes.write(" return ret\n")
+
classes.write("\n");
txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
@@ -896,9 +942,9 @@
classes.write(classes_type[arg[1]][0])
n = n + 1
classes.write(")\n");
- if function_post.has_key(name):
- classes.write(" %s\n" % (function_post[name]));
- if ret[0] != "void":
+
+ # For functions returning object types:
+ if ret[0] != "void":
if classes_type.has_key(ret[0]):
#
# Raise an exception
@@ -911,10 +957,6 @@
classes.write(
" if ret is None:raise libvirtError('%s() failed', conn=self)\n" %
(name))
- elif classname == "virDomain":
- classes.write(
- " if ret is None:raise libvirtError('%s() failed')\n" %
- (name))
else:
classes.write(
" if ret is None:raise libvirtError('%s() failed')\n" %
@@ -945,6 +987,12 @@
if pref[0] == classname:
classes.write(" __tmp.%s = self\n" %
pref[1])
+
+ # Post-processing - just before we return.
+ if function_post.has_key(name):
+ classes.write(" %s\n" %
+ (function_post[name]));
+
#
# return the class
#
@@ -956,11 +1004,59 @@
if functions_noexcept.has_key(name):
classes.write(
" if ret is None:return None");
+
+ # Post-processing - just before we return.
+ if function_post.has_key(name):
+ classes.write(" %s\n" %
+ (function_post[name]));
+
classes.write(" return ");
classes.write(converter_type[ret[0]] % ("ret"));
classes.write("\n");
+
+ # For functions returning an integral type there
+ # are several things that we can do, depending on
+ # the contents of functions_int_*:
+ elif is_integral_type (ret[0]):
+ if functions_int_exception_test.has_key (name):
+ test = functions_int_exception_test[name]
+ else:
+ test = functions_int_default_test
+ classes.write ((" if " + test +
+ ": raise libvirtError ('%s() failed')\n") %
+ ("ret", name))
+
+ # Post-processing - just before we return.
+ if function_post.has_key(name):
+ classes.write(" %s\n" %
+ (function_post[name]));
+
+ classes.write (" return ret\n")
+
+ elif is_list_type (ret[0]):
+ if functions_list_exception_test.has_key (name):
+ test = functions_list_exception_test[name]
+ else:
+ test = functions_list_default_test
+ classes.write ((" if " + test +
+ ": raise libvirtError ('%s() failed')\n") %
+ ("ret", name))
+
+ # Post-processing - just before we return.
+ if function_post.has_key(name):
+ classes.write(" %s\n" %
+ (function_post[name]));
+
+ classes.write (" return ret\n")
+
else:
+ # Post-processing - just before we return.
+ if function_post.has_key(name):
+ classes.write(" %s\n" %
+ (function_post[name]));
+
classes.write(" return ret\n");
+
classes.write("\n");
#
--- libvirt-20070322/python/libvirtclass.py 2007-03-27 11:39:36.000000000 +0100
+++ libvirt-20070327/python/libvirtclass.py 2007-03-27 12:42:27.000000000 +0100
@@ -23,6 +23,7 @@
startup in multithreaded applications to avoid potential
race when initializing the library. """
ret = libvirtmod.virInitialize()
+ if ret == -1: raise libvirtError ('virInitialize() failed')
return ret
#
@@ -57,17 +58,20 @@
def ID(self):
"""Get the hypervisor ID number for the domain """
ret = libvirtmod.virDomainGetID(self._o)
+ if ret == -1: raise libvirtError ('virDomainGetID() failed')
return ret
def OSType(self):
"""Get the type of domain operation system. """
ret = libvirtmod.virDomainGetOSType(self._o)
+ if ret is None: raise libvirtError ('virDomainGetOSType() failed')
return ret
def UUIDString(self, buf):
"""Get the UUID for a domain as string. For more information
about UUID see RFC4122. """
ret = libvirtmod.virDomainGetUUIDString(self._o, buf)
+ if ret == -1: raise libvirtError ('virDomainGetUUIDString() failed')
return ret
def XMLDesc(self, flags):
@@ -75,11 +79,13 @@
may be reused later to relaunch the domain with
virDomainCreateLinux(). """
ret = libvirtmod.virDomainGetXMLDesc(self._o, flags)
+ if ret is None: raise libvirtError ('virDomainGetXMLDesc() failed')
return ret
def attachDevice(self, xml):
"""Create a virtual device attachment to backend. """
ret = libvirtmod.virDomainAttachDevice(self._o, xml)
+ if ret == -1: raise libvirtError ('virDomainAttachDevice() failed')
return ret
def coreDump(self, to, flags):
@@ -87,12 +93,14 @@
for analysis. Note that for remote Xen Daemon the file
path will be interpreted in the remote host. """
ret = libvirtmod.virDomainCoreDump(self._o, to, flags)
+ if ret == -1: raise libvirtError ('virDomainCoreDump() failed')
return ret
def create(self):
"""launch a defined domain. If the call succeed the domain
moves from the defined to the running domains pools. """
ret = libvirtmod.virDomainCreate(self._o)
+ if ret == -1: raise libvirtError ('virDomainCreate() failed')
return ret
def destroy(self):
@@ -102,12 +110,14 @@
should not be used thereafter if the call does not return
an error. This function may requires priviledged access """
ret = libvirtmod.virDomainDestroy(self._o)
+ if ret == -1: raise libvirtError ('virDomainDestroy() failed')
self._o = None
return ret
def detachDevice(self, xml):
"""Destroy a virtual device attachment to backend. """
ret = libvirtmod.virDomainDetachDevice(self._o, xml)
+ if ret == -1: raise libvirtError ('virDomainDetachDevice() failed')
return ret
def maxMemory(self):
@@ -116,6 +126,7 @@
memory reserved to Domain0 i.e. the domain where the
application runs. """
ret = libvirtmod.virDomainGetMaxMemory(self._o)
+ if ret == 0: raise libvirtError ('virDomainGetMaxMemory() failed')
return ret
def maxVcpus(self):
@@ -125,11 +136,13 @@
this will reflect the maximum number of virtual CPUs the
guest was booted with. """
ret = libvirtmod.virDomainGetMaxVcpus(self._o)
+ if ret == -1: raise libvirtError ('virDomainGetMaxVcpus() failed')
return ret
def name(self):
"""Get the public name for that domain """
ret = libvirtmod.virDomainGetName(self._o)
+ if ret is None: raise libvirtError ('virDomainGetName() failed')
return ret
def pinVcpu(self, vcpu, cpumap, maplen):
@@ -137,6 +150,7 @@
a virtual CPU. This function requires priviledged access
to the hypervisor. """
ret = libvirtmod.virDomainPinVcpu(self._o, vcpu, cpumap, maplen)
+ if ret == -1: raise libvirtError ('virDomainPinVcpu() failed')
return ret
def reboot(self, flags):
@@ -144,6 +158,7 @@
after but the domain OS is being stopped for a restart.
Note that the guest OS may ignore the request. """
ret = libvirtmod.virDomainReboot(self._o, flags)
+ if ret == -1: raise libvirtError ('virDomainReboot() failed')
return ret
def resume(self):
@@ -152,6 +167,7 @@
virSuspendDomain(). This function may requires priviledged
access """
ret = libvirtmod.virDomainResume(self._o)
+ if ret == -1: raise libvirtError ('virDomainResume() failed')
return ret
def save(self, to):
@@ -161,12 +177,14 @@
problem). Use virDomainRestore() to restore a domain after
saving. """
ret = libvirtmod.virDomainSave(self._o, to)
+ if ret == -1: raise libvirtError ('virDomainSave() failed')
return ret
def setAutostart(self, autostart):
"""Configure the domain to be automatically started when the
host machine boots. """
ret = libvirtmod.virDomainSetAutostart(self._o, autostart)
+ if ret == -1: raise libvirtError ('virDomainSetAutostart() failed')
return ret
def setMaxMemory(self, memory):
@@ -176,6 +194,7 @@
where the application runs. This function requires
priviledged access to the hypervisor. """
ret = libvirtmod.virDomainSetMaxMemory(self._o, memory)
+ if ret == -1: raise libvirtError ('virDomainSetMaxMemory() failed')
return ret
def setMemory(self, memory):
@@ -185,6 +204,7 @@
where the application runs. This function may requires
priviledged access to the hypervisor. """
ret = libvirtmod.virDomainSetMemory(self._o, memory)
+ if ret == -1: raise libvirtError ('virDomainSetMemory() failed')
return ret
def setVcpus(self, nvcpus):
@@ -194,6 +214,7 @@
growing the number is arbitrary limited. This function
requires priviledged access to the hypervisor. """
ret = libvirtmod.virDomainSetVcpus(self._o, nvcpus)
+ if ret == -1: raise libvirtError ('virDomainSetVcpus() failed')
return ret
def shutdown(self):
@@ -203,6 +224,7 @@
option for reboot, knowing it may not be doable in the
general case ? """
ret = libvirtmod.virDomainShutdown(self._o)
+ if ret == -1: raise libvirtError ('virDomainShutdown() failed')
return ret
def suspend(self):
@@ -212,11 +234,13 @@
allocated. Use virDomainResume() to reactivate the domain.
This function may requires priviledged access. """
ret = libvirtmod.virDomainSuspend(self._o)
+ if ret == -1: raise libvirtError ('virDomainSuspend() failed')
return ret
def undefine(self):
"""undefine a domain but does not stop it if it is running """
ret = libvirtmod.virDomainUndefine(self._o)
+ if ret == -1: raise libvirtError ('virDomainUndefine() failed')
return ret
#
@@ -226,6 +250,7 @@
def UUID(self):
"""Extract the UUID unique Identifier of a domain. """
ret = libvirtmod.virDomainGetUUID(self._o)
+ if ret is None: raise libvirtError ('virDomainGetUUID() failed')
return ret
def info(self):
@@ -233,6 +258,7 @@
connection used to get the domain is limited only a
partial set of the informations can be extracted. """
ret = libvirtmod.virDomainGetInfo(self._o)
+ if ret is None: raise libvirtError ('virDomainGetInfo() failed')
return ret
class virNetwork:
@@ -253,6 +279,7 @@
"""Get the UUID for a network as string. For more information
about UUID see RFC4122. """
ret = libvirtmod.virNetworkGetUUIDString(self._o, buf)
+ if ret == -1: raise libvirtError ('virNetworkGetUUIDString() failed')
return ret
def XMLDesc(self, flags):
@@ -260,12 +287,14 @@
may be reused later to relaunch the network with
virNetworkCreateXML(). """
ret = libvirtmod.virNetworkGetXMLDesc(self._o, flags)
+ if ret is None: raise libvirtError ('virNetworkGetXMLDesc() failed')
return ret
def bridgeName(self):
"""Provides a bridge interface name to which a domain may
connect a network interface in order to join the network. """
ret = libvirtmod.virNetworkGetBridgeName(self._o)
+ if ret is None: raise libvirtError ('virNetworkGetBridgeName() failed')
return ret
def create(self):
@@ -273,6 +302,7 @@
network moves from the defined to the running networks
pools. """
ret = libvirtmod.virNetworkCreate(self._o)
+ if ret == -1: raise libvirtError ('virNetworkCreate() failed')
return ret
def destroy(self):
@@ -283,23 +313,27 @@
not return an error. This function may requires
priviledged access """
ret = libvirtmod.virNetworkDestroy(self._o)
+ if ret == -1: raise libvirtError ('virNetworkDestroy() failed')
self._o = None
return ret
def name(self):
"""Get the public name for that network """
ret = libvirtmod.virNetworkGetName(self._o)
+ if ret is None: raise libvirtError ('virNetworkGetName() failed')
return ret
def setAutostart(self, autostart):
"""Configure the network to be automatically started when the
host machine boots. """
ret = libvirtmod.virNetworkSetAutostart(self._o, autostart)
+ if ret == -1: raise libvirtError ('virNetworkSetAutostart() failed')
return ret
def undefine(self):
"""Undefine a network but does not stop it if it is running """
ret = libvirtmod.virNetworkUndefine(self._o)
+ if ret == -1: raise libvirtError ('virNetworkUndefine() failed')
return ret
#
@@ -309,6 +343,7 @@
def UUID(self):
"""Extract the UUID unique Identifier of a network. """
ret = libvirtmod.virNetworkGetUUID(self._o)
+ if ret is None: raise libvirtError ('virNetworkGetUUID() failed')
return ret
def networkLookupByUUID(self, uuid):
@@ -366,6 +401,7 @@
def getCapabilities(self):
"""Provides capabilities of the hypervisor / driver. """
ret = libvirtmod.virConnectGetCapabilities(self._o)
+ if ret is None: raise libvirtError ('virConnectGetCapabilities() failed')
return ret
def getMaxVcpus(self, type):
@@ -374,11 +410,13 @@
corresponds to the 'type' attribute in the <domain>
element of the XML. """
ret = libvirtmod.virConnectGetMaxVcpus(self._o, type)
+ if ret == -1: raise libvirtError ('virConnectGetMaxVcpus() failed')
return ret
def getType(self):
"""Get the name of the Hypervisor software used. """
ret = libvirtmod.virConnectGetType(self._o)
+ if ret is None: raise libvirtError ('virConnectGetType() failed')
return ret
def lookupByID(self, id):
@@ -436,27 +474,32 @@
def numOfDefinedDomains(self):
"""Provides the number of active domains. """
ret = libvirtmod.virConnectNumOfDefinedDomains(self._o)
+ if ret == -1: raise libvirtError ('virConnectNumOfDefinedDomains() failed')
return ret
def numOfDefinedNetworks(self):
"""Provides the number of inactive networks. """
ret = libvirtmod.virConnectNumOfDefinedNetworks(self._o)
+ if ret == -1: raise libvirtError ('virConnectNumOfDefinedNetworks() failed')
return ret
def numOfDomains(self):
"""Provides the number of active domains. """
ret = libvirtmod.virConnectNumOfDomains(self._o)
+ if ret == -1: raise libvirtError ('virConnectNumOfDomains() failed')
return ret
def numOfNetworks(self):
"""Provides the number of active networks. """
ret = libvirtmod.virConnectNumOfNetworks(self._o)
+ if ret == -1: raise libvirtError ('virConnectNumOfNetworks() failed')
return ret
def restore(self, frm):
"""This method will restore a domain saved to disk by
virDomainSave(). """
ret = libvirtmod.virDomainRestore(self._o, frm)
+ if ret == -1: raise libvirtError ('virDomainRestore() failed')
return ret
#
@@ -466,29 +509,34 @@
def getInfo(self):
"""Extract hardware informations about the Node. """
ret = libvirtmod.virNodeGetInfo(self._o)
+ if ret is None: raise libvirtError ('virNodeGetInfo() failed')
return ret
def listDefinedDomains(self):
"""list the defined domains, stores the pointers to the names
in @names """
ret = libvirtmod.virConnectListDefinedDomains(self._o)
+ if ret is None: raise libvirtError ('virConnectListDefinedDomains() failed')
return ret
def listDefinedNetworks(self):
"""list the defined networks, stores the pointers to the names
in @names """
ret = libvirtmod.virConnectListDefinedNetworks(self._o)
+ if ret is None: raise libvirtError ('virConnectListDefinedNetworks() failed')
return ret
def listDomainsID(self):
"""Returns the list of the ID of the domains on the hypervisor """
ret = libvirtmod.virConnectListDomainsID(self._o)
+ if ret is None: raise libvirtError ('virConnectListDomainsID() failed')
return ret
def listNetworks(self):
"""list the networks, stores the pointers to the names in
@names """
ret = libvirtmod.virConnectListNetworks(self._o)
+ if ret is None: raise libvirtError ('virConnectListNetworks() failed')
return ret
def lookupByUUID(self, uuid):
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature