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