Noriko Hosoi wrote:
Richard Megginson wrote:
Noriko Hosoi wrote:
Richard Megginson wrote:
Noriko Hosoi wrote:
Bugzilla Bug 202843 <https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=202843>: referential integrity plugin does not stack with Class of Service appliance

I'm investigating this bug.  It looks like a tricky one.  I used the sample data the reporter provided:
Comment #1 <https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=202843#c1> >From Hai Zaar (haizaar@gmail.com <mailto:haizaar@gmail.com>)     on 2006-08-16 14:36 EST     [reply <https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=202843#add_comment>]     Private

Created an attachment (id=134332) <https://bugzilla.redhat.com/bugzilla/attachment.cgi?id=134332> [edit <https://bugzilla.redhat.com/bugzilla/attachment.cgi?id=134332&action=edit>]
LDIF for bug reproduction
  Following is the costemplate and an entry that shows attribute derived from CoS (uniqueMember):

    $ ./ldapsearch -p <port> -D "cn=Directory Manager" -w <password>
    -b "ou=PosixGroups,dc=example,dc=com" "(uniqueMember=*)"
    version: 1
    dn: cn=uids,ou=PosixGroups,dc=example,dc=com
    cosPriority: 1
    cn: uids
    objectClass: top
    objectClass: costemplate
    objectClass: extensibleobject
    uniqueMember: uid=gilran,ou=people,dc=example,dc=com
    uniqueMember: uid=haizaar,ou=people,dc=example,dc=com

    dn: cn=testgroup,ou=PosixGroups,dc=example,dc=com
    gidNumber: 503
    objectClass: top
    objectClass: posixgroup
    objectClass: groupofuniquenames
    cn: testgroup
    uniqueMember: uid=gilran,ou=people,dc=example,dc=com
    uniqueMember: uid=haizaar,ou=people,dc=example,dc=com

I turned on the referential integrity, and removed an entry (dn: uid=gilran,ou=people,dc=example,dc=com).

Then, the uniqueMember in the CoS template was successfully removed.  But the testgroup entry still shows the deleted uniqueMember:

    $ ./ldapsearch -p <port> -D "cn=Directory Manager" -w <password>
    -b "ou=PosixGroups,dc=example,dc=com" "(uniqueMember=*)"
    version: 1
    dn: cn=uids,ou=PosixGroups,dc=example,dc=com
    cosPriority: 1
    cn: uids
    objectClass: top
    objectClass: costemplate
    objectClass: extensibleobject
    uniqueMember: uid=haizaar,ou=people,dc=example,dc=com

    dn: cn=testgroup,ou=PosixGroups,dc=example,dc=com
    gidNumber: 503
    objectClass: top
    objectClass: posixgroup
    objectClass: groupofuniquenames
    cn: testgroup
    uniqueMember: uid=gilran,ou=people,dc=example,dc=com
    uniqueMember: uid=haizaar,ou=people,dc=example,dc=com

CoS has a cache and only when an entry that is related to CoS is updated (checked in cos_cache_entry_is_cos_related), the cache is updated by cos_cache_change_notify.  I manually sent notify in the debugger (set do_update = 1), then the removed uniqueMember was deleted both from the CoS template and the testgroup.

    $ ./ldapsearch -p <port> -D "cn=Directory Manager" -w <password>
    -b "ou=PosixGroups,dc=example,dc=com" "(uniqueMember=*)"
    version: 1
    dn: cn=uids,ou=PosixGroups,dc=example,dc=com
    cosPriority: 1
    cn: uids
    objectClass: top
    objectClass: costemplate
    objectClass: extensibleobject
    uniqueMember: uid=haizaar,ou=people,dc=example,dc=com

    dn: cn=testgroup,ou=PosixGroups,dc=example,dc=com
    gidNumber: 503
    objectClass: top
    objectClass: posixgroup
    objectClass: groupofuniquenames
    cn: testgroup
    uniqueMember: uid=haizaar,ou=people,dc=example,dc=com

So, it seems what's needed is having post plugins for the referential integrity plugin... :)  Certainly, it sounds not too realistic (or am I wrong???)  Alternatively, instead of using the internal operations, the referential integrity plugin could call the external operation (that would make the post plugins available.  But of course, the performance should get even worse when the referential integrity plugin is on.)  Or shall we drop the coexistence as for MMR and referential integrity?
It sounds like we need some sort of priority system for plugins, so that you can call plugins in a certain order.  In this case, we would call refint first, then cos.  We used to have this with the old slapd.conf style (I think they used to be called in the order they were listed).  Other servers that support plugins have some way to set the order of plugin execution - Apache has a fairly sophisticated module calling order (i.e. you can give a numeric priority, or you can say "module A must be called after module B", or you can say "module C must always be called first").  Even OpenLDAP overlays can be "stacked" in a way such that the order matters.
Thank for your comments, Rich.  As you mentioned, CoS is called prior to Referential Integrity plugin.  I expected that we could change the execution order by setting "nsslapd-plugin-depends-on-named", but it's used for plugins' loading, not for the execution order.  (right?)
Right.

Maybe we could use the dependency for the execution order, as well?
I don't think that will work.  Load dependency and call order are different, and I'm sure we would run into problems, even if it worked in this case.
Okay.  I need to think about it more in depth... :)
If you want some ideas, take a look at Apache 2.2.  In Apache, the modules are loaded in the order they are listed in the httpd.conf file (this corresponds to what happens during our plugin "init" phase).  Then, you can configure everything else after that, starting from the startup phase (roughly, our plugin "start" phase).
For example, from mod_admserv.c:
static void register_hooks(apr_pool_t *p) /* called during module load */
{
...
   static const char * const aszPost[] = { "mod_auth_basic.c", NULL };
   /* Make sure mod_nss has been configured before us */
   static const char * const aszPre[] = { "mod_nss.c", NULL };
...
   /* this tells Apache to always call the pre_config and post_config functions in the module named "mod_nss.c"
      before calling our pre_config and post_config functions */
   ap_hook_pre_config(mod_admserv_pre_config, aszPre, NULL, APR_HOOK_MIDDLE);
   ap_hook_post_config(mod_admserv_post_config, aszPre, NULL, APR_HOOK_MIDDLE);
...
   /* This tells Apache to always call the check_user_id function in the module named "mod_auth_basic.c"
      after calling our check_user_id function i.e. fallback to basic auth if ldap auth fails */
   ap_hook_check_user_id(admserv_check_user_id, NULL, aszPost, APR_HOOK_MIDDLE);

You might also take a look at OpenLDAP 2.3 to see how they stack overlays to be called in order.