This is required for effective filtering of enrollments search
results in the webUI and also gives an edge to the CLI.

After this patch, each LDAPObject can define its relationships
to other LDAPObjects. For now, this is used only for filtering
search results by enrollments, but there are probably more
benefits to come.

You can do this for example:

# search for all users not enrolled in group admins
ipa user-find --not-in-groups=admins

# search for all groups not enrolled in group global with user Pavel
ipa group-find --users=Pavel --not-in-groups=global

# more examples:
ipa group-find --users=Pavel,Jakub --no-users=Honza
ipa hostgroup-find --hosts=webui.pzuna

Pavel
>From 19975e5e2ceb3a3f9fd18be0f3fafe8f42aa626c Mon Sep 17 00:00:00 2001
From: Pavel Zuna <pz...@redhat.com>
Date: Tue, 4 Jan 2011 15:15:54 -0500
Subject: [PATCH 1/2] Improve filtering of enrollments search results.

This is required for effective filtering of enrollments search
results in the webUI and also gives an edge to the CLI.

After this patch, each LDAPObject can define its relationships
to other LDAPObjects. For now, this is used only for filtering
search results by enrollments, but there are probably more
benefits to come.

You can do this for example:

# search for all users not enrolled in group admins
ipa user-find --not-in-groups=admins

# search for all groups not enrolled in group global with user Pavel
ipa group-find --users=Pavel --not-in-groups=global

# more examples:
ipa group-find --users=Pavel,Jakub --no-users=Honza
ipa hostgroup-find --hosts=webui.pzuna
---
 ipalib/plugins/baseldap.py  |   57 ++++++++++++++++++++++++++++++++++++-------
 ipalib/plugins/group.py     |    2 +-
 ipalib/plugins/host.py      |    7 ++++-
 ipalib/plugins/hostgroup.py |    2 +-
 ipalib/plugins/netgroup.py  |   11 +++++++-
 ipalib/plugins/user.py      |    2 +
 6 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 1cd181c..d38da89 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -234,6 +234,15 @@ class LDAPObject(Object):
     rdnattr = None
     # Can bind as this entry (has userPassword or krbPrincipalKey)
     bindable = False
+    relationships = {
+        # attribute: (label, inclusive param prefix, exclusive param prefix)
+        'member': ('Member', '', 'no_'),
+        'memberof': ('Parent', 'in_', 'not_in_'),
+        'memberindirect': (
+            'Indirect Member', None, 'no_indirect_'
+        ),
+    }
+    label = _('Entry')
 
     container_not_found_msg = _('container entry (%(container)s) not found')
     parent_not_found_msg = _('%(parent)s: %(oname)s not found')
@@ -343,7 +352,7 @@ class LDAPObject(Object):
         'parent_object', 'container_dn', 'object_name', 'object_name_plural',
         'object_class', 'object_class_config', 'default_attributes', 'label',
         'hidden_attributes', 'uuid_attribute', 'attribute_members', 'name',
-        'takes_params', 'rdn_attribute', 'bindable',
+        'takes_params', 'rdn_attribute', 'bindable', 'relationships',
     )
 
     def __json__(self):
@@ -1195,7 +1204,8 @@ class LDAPSearch(CallbackInterface, crud.Search):
     Retrieve all LDAP entries matching the given criteria.
     """
     member_attributes = []
-    member_param_doc = 'exclude %s with member %s (comma-separated list)'
+    member_param_incl_doc = 'only %s with %s %s'
+    member_param_excl_doc = 'only %s with no %s %s'
 
     takes_options = (
         Int('timelimit?',
@@ -1227,21 +1237,50 @@ class LDAPSearch(CallbackInterface, crud.Search):
         for attr in self.member_attributes:
             for ldap_obj_name in self.obj.attribute_members[attr]:
                 ldap_obj = self.api.Object[ldap_obj_name]
-                name = to_cli(ldap_obj_name)
-                doc = self.member_param_doc % (
-                    self.obj.object_name_plural, ldap_obj.object_name_plural
+                relationship = self.obj.relationships.get(
+                    attr, ['member', '', 'no_']
+                )
+                doc = self.member_param_incl_doc % (
+                    self.obj.object_name_plural, relationship[0].lower(),
+                    ldap_obj.object_name_plural
+                )
+                name = '%s%s' % (relationship[1], to_cli(ldap_obj_name))
+                yield List(
+                    '%s?' % name, cli_name='%ss' % name, doc=doc,
+                    label=ldap_obj.object_name
+                )
+                doc = self.member_param_excl_doc % (
+                    self.obj.object_name_plural, relationship[0].lower(),
+                    ldap_obj.object_name_plural
+                )
+                name = '%s%s' % (relationship[2], to_cli(ldap_obj_name))
+                yield List(
+                    '%s?' % name, cli_name='%ss' % name, doc=doc,
+                    label=ldap_obj.object_name
                 )
-                yield List('no_%s?' % name, cli_name='no_%ss' % name, doc=doc,
-                           label=ldap_obj.object_name)
 
     def get_member_filter(self, ldap, **options):
         filter = ''
         for attr in self.member_attributes:
             for ldap_obj_name in self.obj.attribute_members[attr]:
-                param_name = 'no_%s' % to_cli(ldap_obj_name)
+                ldap_obj = self.api.Object[ldap_obj_name]
+                relationship = self.obj.relationships.get(
+                    attr, ['member', '', 'no_']
+                )
+                param_name = '%s%s' % (relationship[1], to_cli(ldap_obj_name))
+                if param_name in options:
+                    dns = []
+                    for pkey in options[param_name]:
+                        dns.append(ldap_obj.get_dn(pkey))
+                    flt = ldap.make_filter_from_attr(
+                        attr, dns, ldap.MATCH_ALL
+                    )
+                    filter = ldap.combine_filters(
+                        (filter, flt), ldap.MATCH_ALL
+                    )
+                param_name = '%s%s' % (relationship[2], to_cli(ldap_obj_name))
                 if param_name in options:
                     dns = []
-                    ldap_obj = self.api.Object[ldap_obj_name]
                     for pkey in options[param_name]:
                         dns.append(ldap_obj.get_dn(pkey))
                     flt = ldap.make_filter_from_attr(
diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py
index 9fd2400..ecf5453 100644
--- a/ipalib/plugins/group.py
+++ b/ipalib/plugins/group.py
@@ -213,7 +213,7 @@ class group_find(LDAPSearch):
     """
     Search for groups.
     """
-    member_attributes = ['member']
+    member_attributes = ['member', 'memberof']
 
     msg_summary = ngettext(
         '%(count)d group matched', '%(count)d groups matched', 0
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index 701996b..821673f 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -170,6 +170,11 @@ class host(LDAPObject):
         'managedby': ['host'],
     }
     bindable = True
+    relationships = {
+        'memberof': ('Parent', 'in_', 'not_in_'),
+        'enrolledby': ('Enrolled by', 'enroll_by_', 'not_enroll_by_'),
+        'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
+    }
 
     label = _('Hosts')
 
@@ -568,7 +573,7 @@ class host_find(LDAPSearch):
     msg_summary = ngettext(
         '%(count)d host matched', '%(count)d hosts matched'
     )
-    member_attributes = ['managedby']
+    member_attributes = ['memberof', 'enrolledby', 'managedby']
 
     def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
         if 'locality' in attrs_list:
diff --git a/ipalib/plugins/hostgroup.py b/ipalib/plugins/hostgroup.py
index db270ae..082e4ef 100644
--- a/ipalib/plugins/hostgroup.py
+++ b/ipalib/plugins/hostgroup.py
@@ -123,7 +123,7 @@ class hostgroup_find(LDAPSearch):
     """
     Search for hostgroups.
     """
-    member_attributes = ['member']
+    member_attributes = ['member', 'memberof']
     msg_summary = ngettext(
         '%(count)d hostgroup matched', '%(count)d hostgroups matched'
     )
diff --git a/ipalib/plugins/netgroup.py b/ipalib/plugins/netgroup.py
index 83e6999..ce9a51b 100644
--- a/ipalib/plugins/netgroup.py
+++ b/ipalib/plugins/netgroup.py
@@ -85,6 +85,15 @@ class netgroup(LDAPObject):
         'memberuser': ['user', 'group'],
         'memberhost': ['host', 'hostgroup'],
     }
+    relationships = {
+        'member': ('Member', '', 'no_'),
+        'memberof': ('Parent', 'in_', 'not_in_'),
+        'memberindirect': (
+            'Indirect Member', None, 'no_indirect_'
+        ),
+        'memberuser': ('Member', '', 'no_'),
+        'memberhost': ('Member', '', 'no_'),
+    }
 
     label = _('Net Groups')
 
@@ -171,7 +180,7 @@ class netgroup_find(LDAPSearch):
     """
     Search for a netgroup.
     """
-    member_attributes = ['member', 'memberuser', 'memberhost']
+    member_attributes = ['member', 'memberuser', 'memberhost', 'memberof']
     has_output_params = LDAPSearch.has_output_params + output_params
     msg_summary = ngettext(
         '%(count)d netgroup matched', '%(count)d netgroups matched'
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 9ccd216..30abf49 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -315,6 +315,7 @@ class user_find(LDAPSearch):
     """
     Search for users.
     """
+    member_attributes = ['memberof']
 
     takes_options = LDAPSearch.takes_options + (
         Flag('whoami',
@@ -322,6 +323,7 @@ class user_find(LDAPSearch):
             doc=_('Display user record for current Kerberos principal'),
         ),
     )
+
     def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options):
         if options.get('whoami'):
             return ("(&(objectclass=posixaccount)(krbprincipalname=%s))"%\
-- 
1.7.1.1

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

Reply via email to