On 2010-05-10 20:38, Rob Crittenden wrote:
Pavel Zuna wrote:
The new callback enables plugin authors to supply their own handler
for ExecutionError exceptions generated by calls to ldap2 made from
the execute method of baseldap.py classes that extend CallbackInterface.

Pavel

I don't see any reference to EXC_CALLBACKS other than in registration.
It looks like this provides a registration system then just calls the
top exc_callback call.
My mistake, fixed patch attached.

I see the default exc_callback() is just a raise. I think this should
always be called last to raise the exception if things get that far.
This way the plugin author doesn't have to remember to raise themselves
if whatever condition they're looking for isn't met (which your second
patch doesn't do).
We can't always call the default callback last, because all registered callbacks are called in a row and therefore the exception would always be raised. We want to be able to suppress exceptions.

Just to make things a little more clear: The default callbacks (the {pre,post,exc}_callback methods) are there to be overridden by plugin authors. Registering new callbacks is a way to extend existing plugins.

I also modified the way we call exception callbacks in this version of the patch, so that we can simulate that nothing went wrong even for ldap2 calls that return values. Also if a callback raises an ExecutionError, the callbacks called next have a chance to handle it.

I like where this is going, just needs a little more work.

rob

Pavel
From 3ff35b30be65f50e32e6373f76a038b0483efa28 Mon Sep 17 00:00:00 2001
From: Pavel Zuna <pz...@redhat.com>
Date: Mon, 10 May 2010 14:26:51 +0200
Subject: [PATCH 1/2] Add exception callback (exc_callback) to baseldap.py 
classes.

It enables plugin authors to supply their own handlers for
ExecutionError exceptions generated by calls to ldap2 made from
the execute method of baseldap.py classes that extend CallbackInterface.
---
 ipalib/plugins/baseldap.py |  177 +++++++++++++++++++++++++++++++++++--------
 1 files changed, 144 insertions(+), 33 deletions(-)

diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index e484137..19390e9 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -144,10 +144,14 @@ class CallbackInterface(Method):
             self.__class__.PRE_CALLBACKS = []
         if not hasattr(self.__class__, 'POST_CALLBACKS'):
             self.__class__.POST_CALLBACKS = []
+        if not hasattr(self.__class__, 'EXC_CALLBACKS'):
+            self.__class__.EXC_CALLBACKS = []
         if hasattr(self, 'pre_callback'):
             self.register_pre_callback(self.pre_callback, True)
         if hasattr(self, 'post_callback'):
             self.register_post_callback(self.post_callback, True)
+        if hasattr(self, 'exc_callback'):
+            self.register_exc_callback(self.exc_callback, True)
         super(Method, self).__init__()
 
     @classmethod
@@ -170,6 +174,31 @@ class CallbackInterface(Method):
         else:
             klass.POST_CALLBACKS.append(callback)
 
+    @classmethod
+    def register_exc_callback(klass, callback, first=False):
+        assert callable(callback)
+        if not hasattr(klass, 'EXC_CALLBACKS'):
+            klass.EXC_CALLBACKS = []
+        if first:
+            klass.EXC_CALLBACKS.insert(0, callback)
+        else:
+            klass.EXC_CALLBACKS.append(callback)
+
+    def _call_exc_callbacks(self, *args, **kwargs):
+        rv = None
+        for i in xrange(len(getattr(self, 'EXC_CALLBACKS', []))):
+            callback = self.EXC_CALLBACKS[i]
+            try:
+                if hasattr(callback, 'im_self'):
+                    rv = callback(*args, **kwargs)
+                else:
+                    rv = callback(self, *args, **kwargs)
+            except errors.ExecutionError, e:
+                if (i + 1) < len(self.EXC_CALLBACKS):
+                    continue
+                raise e
+        return rv
+
 
 class LDAPCreate(CallbackInterface, crud.Create):
     """
@@ -219,27 +248,39 @@ class LDAPCreate(CallbackInterface, crud.Create):
 
         try:
             ldap.add_entry(dn, entry_attrs, normalize=self.obj.normalize_dn)
-        except errors.NotFound:
-            parent = self.obj.parent_object
-            if parent:
+        except errors.ExecutionError, e:
+            try:
+                self._call_exc_callbacks(
+                    keys, options, e, ldap.add_entry, dn, entry_attrs,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                parent = self.obj.parent_object
+                if parent:
+                    raise errors.NotFound(
+                        reason=self.obj.parent_not_found_msg % {
+                            'parent': keys[-2],
+                            'oname': self.api.Object[parent].object_name,
+                        }
+                    )
                 raise errors.NotFound(
-                    reason=self.obj.parent_not_found_msg % {
-                        'parent': keys[-2],
-                        'oname': self.api.Object[parent].object_name,
+                    reason=self.obj.container_not_found_msg % {
+                        'container': self.obj.container_dn,
                     }
                 )
-            raise errors.NotFound(
-                reason=self.obj.container_not_found_msg % {
-                    'container': self.obj.container_dn,
-                }
-            )
 
         try:
             (dn, entry_attrs) = ldap.get_entry(
                 dn, attrs_list, normalize=self.obj.normalize_dn
             )
-        except errors.NotFound:
-            self.obj.handle_not_found(*keys)
+        except errors.ExecutionError, e:
+            try:
+                (dn, entry_attrs) = self._call_exc_callbacks(
+                    keys, options, e, ldap.get_entry, dn, attrs_list,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                self.obj.handle_not_found(*keys)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
@@ -260,6 +301,9 @@ class LDAPCreate(CallbackInterface, crud.Create):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         return dn
 
+    def exc_callback(self, keys, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
 
 class LDAPQuery(CallbackInterface, crud.PKQuery):
     """
@@ -298,8 +342,14 @@ class LDAPRetrieve(LDAPQuery):
             (dn, entry_attrs) = ldap.get_entry(
                 dn, attrs_list, normalize=self.obj.normalize_dn
             )
-        except errors.NotFound:
-            self.obj.handle_not_found(*keys)
+        except errors.ExecutionError, e:
+            try:
+                (dn, entry_attrs) = self._call_exc_callbacks(
+                    keys, options, e, ldap.get_entry, dn, attrs_list,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                self.obj.handle_not_found(*keys)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
@@ -319,6 +369,9 @@ class LDAPRetrieve(LDAPQuery):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         return dn
 
+    def exc_callback(self, keys, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
 
 class LDAPUpdate(LDAPQuery, crud.Update):
     """
@@ -366,8 +419,14 @@ class LDAPUpdate(LDAPQuery, crud.Update):
                 (dn, old_entry) = ldap.get_entry(
                     dn, attrs_list, normalize=self.obj.normalize_dn
                 )
-            except errors.NotFound:
-                self.obj.handle_not_found(*keys)
+            except errors.ExecutionError, e:
+                try:
+                    (dn, old_entry) = self._call_exc_callbacks(
+                        keys, options, e, ldap.get_entry, dn, attrs_list,
+                        normalize=self.obj.normalize_dn
+                    )
+                except errors.NotFound:
+                    self.obj.handle_not_found(*keys)
             attrlist = get_attributes(options['addattr'])
             for attr in attrlist:
                 if attr in old_entry:
@@ -379,17 +438,29 @@ class LDAPUpdate(LDAPQuery, crud.Update):
 
         try:
             ldap.update_entry(dn, entry_attrs, normalize=self.obj.normalize_dn)
-        except errors.NotFound:
-            self.obj.handle_not_found(*keys)
+        except errors.ExecutionError, e:
+            try:
+                self._call_exc_callbacks(
+                    keys, options, e, ldap.update_entry, dn, entry_attrs,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                self.obj.handle_not_found(*keys)
 
         try:
             (dn, entry_attrs) = ldap.get_entry(
                 dn, attrs_list, normalize=self.obj.normalize_dn
             )
-        except errors.NotFound:
-            raise errors.MidairCollision(
-                format=_('the entry was deleted while being modified')
-            )
+        except errors.ExecutionError, e:
+            try:
+                (dn, entry_attrs) = self._call_exc_callbacks(
+                    keys, options, e, ldap.get_entry, dn, attrs_list,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                raise errors.MidairCollision(
+                    format=_('the entry was deleted while being modified')
+                )
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
@@ -408,6 +479,9 @@ class LDAPUpdate(LDAPQuery, crud.Update):
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         return dn
 
+    def exc_callback(self, keys, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
 
 class LDAPDelete(LDAPQuery):
     """
@@ -440,8 +514,14 @@ class LDAPDelete(LDAPQuery):
                         delete_subtree(dn_)
             try:
                 ldap.delete_entry(base_dn, normalize=self.obj.normalize_dn)
-            except errors.NotFound:
-                self.obj.handle_not_found(*keys)
+            except errors.ExecutionError, e:
+                try:
+                    self._call_exc_callbacks(
+                        keys, options, e, ldap.delete_entry, base_dn,
+                        normalize=self.obj.normalize_dn
+                    )
+                except errors.NotFound:
+                    self.obj.handle_not_found(*keys)
 
         delete_subtree(dn)
 
@@ -461,6 +541,9 @@ class LDAPDelete(LDAPQuery):
     def post_callback(self, ldap, dn, *keys, **options):
         return True
 
+    def exc_callback(self, keys, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
 
 class LDAPModMember(LDAPQuery):
     """
@@ -561,16 +644,22 @@ class LDAPAddMember(LDAPModMember):
             (dn, entry_attrs) = ldap.get_entry(
                 dn, attrs_list, normalize=self.obj.normalize_dn
             )
-        except errors.NotFound:
-            self.obj.handle_not_found(*keys)
+        except errors.ExecutionError, e:
+            try:
+                (dn, entry_attrs) = self._call_exc_callbacks(
+                    keys, options, e, ldap.get_entry, dn, attrs_list,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                self.obj.handle_not_found(*keys)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
-                (completed, dn) = self.post_callback(
+                (completed, dn) = callback(
                     ldap, completed, failed, dn, entry_attrs, *keys, **options
                 )
             else:
-                (completed, dn) = self.post_callback(
+                (completed, dn) = callback(
                     self, ldap, completed, failed, dn, entry_attrs, *keys,
                     **options
                 )
@@ -589,6 +678,9 @@ class LDAPAddMember(LDAPModMember):
     def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, 
**options):
         return (completed, dn)
 
+    def exc_callback(self, keys, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
 
 class LDAPRemoveMember(LDAPModMember):
     """
@@ -651,8 +743,14 @@ class LDAPRemoveMember(LDAPModMember):
             (dn, entry_attrs) = ldap.get_entry(
                 dn, attrs_list, normalize=self.obj.normalize_dn
             )
-        except errors.NotFound:
-            self.obj.handle_not_found(*keys)
+        except errors.ExecutionError, e:
+            try:
+                (dn, entry_attrs) = self._call_exc_callbacks(
+                    keys, options, e, ldap.get_entry, dn, attrs_list,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                self.obj.handle_not_found(*keys)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
@@ -680,6 +778,9 @@ class LDAPRemoveMember(LDAPModMember):
     def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, 
**options):
         return (completed, dn)
 
+    def exc_callback(self, keys, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
 
 class LDAPSearch(CallbackInterface, crud.Search):
     """
@@ -738,8 +839,15 @@ class LDAPSearch(CallbackInterface, crud.Search):
             (entries, truncated) = ldap.find_entries(
                 filter, attrs_list, base_dn, scope=ldap.SCOPE_ONELEVEL
             )
-        except errors.NotFound:
-            (entries, truncated) = ([], False)
+        except errors.ExecutionError, e:
+            try:
+                (entries, truncated) = self._call_exc_callbacks(
+                    args, options, e, ldap.find_entries, filter, attrs_list,
+                    base_dn, scoope=ldap.SCOPE_ONELEVEL,
+                    normalize=self.obj.normalize_dn
+                )
+            except errors.NotFound:
+                (entries, truncated) = ([], False)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
@@ -767,3 +875,6 @@ class LDAPSearch(CallbackInterface, crud.Search):
     def post_callback(self, ldap, entries, truncated, *args, **options):
         pass
 
+    def exc_callback(self, args, options, exc, call_func, *call_args, 
**call_kwargs):
+        raise exc
+
-- 
1.6.6.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to