[PATCH] Python bindings now generate exceptions for libvirt errors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Following on from this thread:
https://www.redhat.com/archives/libvir-list/2007-March/thread.html#00341

The 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


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]