Give the memberof plugin time to work when adding/removing reverse members.

When we add/remove reverse members it looks like we're operating on group A but we're really operating on group B. This adds/removes the member attribute on group B and the memberof plugin adds the memberof attribute into group A.

We need to give the memberof plugin a chance to do its work so loop a few times, reading the entry to see if the number of memberof is more or less what we expect. Bail out if it is taking too long.

ticket 560

rob
>From f02cb4f4988e01d651005e182f5c0245121e6fc8 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Tue, 7 Dec 2010 23:22:00 -0500
Subject: [PATCH] Give the memberof plugin time to work when adding/removing reverse members.

When we add/remove reverse members it looks like we're operating on group A
but we're really operating on group B. This adds/removes the member attribute
on group B and the memberof plugin adds the memberof attribute into group A.

We need to give the memberof plugin a chance to do its work so loop a few
times, reading the entry to see if the number of memberof is more or less
what we expect. Bail out if it is taking too long.

ticket 560
---
 ipalib/plugins/baseldap.py |   59 +++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 6b7153b..99d3d4f 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -22,8 +22,9 @@ Base classes for LDAP plugins.
 
 import re
 import json
+import time
 
-from ipalib import crud, errors
+from ipalib import api, crud, errors
 from ipalib import Method, Object
 from ipalib import Flag, Int, List, Str
 from ipalib.base import NameSpace
@@ -175,6 +176,50 @@ def get_effective_rights(ldap, dn, attrs=None):
 
     return rdict
 
+def wait_for_memberof(keys, entry_start, completed, show_command, adding=True):
+    """
+    When adding or removing reverse members we are faking an update to
+    object A by updating the member attribute in object B. The memberof
+    plugin makes this work by adding or removing the memberof attribute
+    to/from object A, it just takes a little bit of time.
+
+    This will loop for 6+ seconds, retrieving object A so we can see
+    if all the memberof attributes have been updated.
+    """
+    if completed == 0:
+        # nothing to do
+        return api.Command[show_command](keys[-1])['result']
+
+    if 'memberof' in entry_start:
+        starting_memberof = len(entry_start['memberof'])
+    else:
+        starting_memberof = 0
+
+    # Loop a few times to give the memberof plugin a chance to add the
+    # entries. Don't sleep for more than 6 seconds.
+    memberof = 0
+    x = 0
+    while x < 20:
+        # sleep first because the first search, even on a quiet system,
+        # almost always fails to have memberof set.
+        time.sleep(.3)
+        x = x + 1
+
+        # FIXME: put a try/except around here? I think it is probably better
+        # to just let the exception filter up to the caller.
+        entry_attrs = api.Command[show_command](keys[-1])['result']
+        if 'memberof' in entry_attrs:
+            memberof = len(entry_attrs['memberof'])
+
+        if adding:
+            if starting_memberof + completed >= memberof:
+                break
+        else:
+            if starting_memberof + completed <= memberof:
+                break
+
+    return entry_attrs
+
 class LDAPObject(Object):
     """
     Object representing a LDAP entry.
@@ -1326,6 +1371,9 @@ class LDAPAddReverseMember(LDAPModReverseMember):
         else:
             attrs_list = self.obj.default_attributes
 
+        # Pull the record as it is now so we can know how many members
+        # there are.
+        entry_start = self.api.Command[self.show_command](keys[-1])['result']
         completed = 0
         failed = {'member': {self.reverse_attr: []}}
         for attr in options.get(self.reverse_attr, []):
@@ -1351,7 +1399,8 @@ class LDAPAddReverseMember(LDAPModReverseMember):
             except errors.PublicError, e:
                 failed['member'][self.reverse_attr].append((attr, unicode(msg)))
 
-        entry_attrs = self.api.Command[self.show_command](keys[-1])['result']
+        # Wait for the memberof plugin to update the entry
+        entry_attrs = wait_for_memberof(keys, entry_start, completed, self.show_command, adding=True)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
@@ -1429,6 +1478,9 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
         else:
             attrs_list = self.obj.default_attributes
 
+        # Pull the record as it is now so we can know how many members
+        # there are.
+        entry_start = self.api.Command[self.show_command](keys[-1])['result']
         completed = 0
         failed = {'member': {self.reverse_attr: []}}
         for attr in options.get(self.reverse_attr, []):
@@ -1454,7 +1506,8 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
             except errors.PublicError, e:
                 failed['member'][self.reverse_attr].append((attr, unicode(msg)))
 
-        entry_attrs = self.api.Command[self.show_command](keys[-1])['result']
+        # Wait for the memberof plugin to update the entry
+        entry_attrs = wait_for_memberof(keys, entry_start, completed, self.show_command, adding=False)
 
         for callback in self.POST_CALLBACKS:
             if hasattr(callback, 'im_self'):
-- 
1.7.2.1

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

Reply via email to