On 11/19/2014 02:03 PM, Jan Cholasta wrote: > Dne 19.11.2014 v 13:44 Tomas Babej napsal(a): >> >> On 11/19/2014 12:51 PM, Martin Kosek wrote: >>> On 11/19/2014 12:41 PM, Tomas Babej wrote: >>>> On 11/19/2014 12:24 PM, Martin Kosek wrote: >>>>> On 11/19/2014 12:03 PM, Tomas Babej wrote: >>>>>> Hi, >>>>>> >>>>>> When constructing a parent DN in LDAPSearch, we should always >>>>>> check that the parent object exists (hence use get_dn_if_exists), >>>>>> rather than search on unexistant containers (which can happen >>>>>> with get_dn). >>>>>> >>>>>> Replaces get_dn calls with get_dn_if_exists in *-find commands >>>>>> and makes sure proper error message is raised. >>>>>> >>>>>> https://fedorahosted.org/freeipa/ticket/4659 >>>>> Doesn't it produce extra LDAP search thus making all our search >>>>> commands >>>>> slower? Is that what we want? >>>> No it does not make all of our LDAP search slower. It only happens for >>>> the objects that have parent objects, such as idoverrides or >>>> dnsrecords. >>> ... and makes them slower. >> >> What I was pointing out here is that this is not a issue for ALL *-find >> commands (e.g user-find, group-find will not suffer from it), as you >> incorrectly stated. >> >>> >>>>> Wouldn't it be better to distinguish between LDAP >>>>> search with no results and LDAP search with missing parent DN? The >>>>> reply looks >>>>> different, at least in CLI: >>>> Up to discussion. We would probably need to introduce a new exception, >>>> like ParentObjectNotFound. >>>> >>>>> # search result >>>>> search: 4 >>>>> result: 0 Success >>>>> >>>>> # search result >>>>> search: 4 >>>>> result: 32 No such object >>>>> matchedDN: cn=accounts,dc=mkosek-f20,dc=test >>>>> >>>>> Also, I do not think you can just stop using get_dn(), some >>>>> commands override >>>>> this call to get more complex searches (like host-find searching >>>>> for shortname). >>>> Look into the get_dn_if_exists, it just wraps around get_dn, so no >>>> issue >>>> here. Any custom behaviour is preserved. >>> Ah, ok, thanks for info. >>> >>>> To sum up, I think this is worth changing this behaviour by default, >>>> ignoring a non-matching value of the parent object is not a correct >>>> general approach in my opinion. >>> Well, that's the question. Whether we would leave DS to validate the >>> search >>> itself or do all the pre-check ourselves. To me, doing just one LDAP >>> search and >>> processing the error correctly looks better. But I can live even >>> with your >>> version then, I will leave the framework guardians like Honza or >>> Petr3 to decide. > > +1 on single LDAP search and proper error processing. > >> >> I see now what you're trying to suggest. However, the reason boils >> down to ipaldap.find_entries method not differentiating between a >> LDAP search that returns error code 32 (No such object) and LDAP >> search returning error code 0 (Success), but returning no results. >> >> In both cases errors.NotFound is raised. >> >> The reason I did not go this way is that changing the find_entries >> method >> is quite more invasive as this is the method subsenqently called by >> almost >> any command. > > You can always derive the new error (ParentNotFound or whatever) on > NotFound, so old code won't break. >
Thanks for the suggestsions. Attached is a new patch which hooks into find_entries method and differentiates between the cases. -- Tomas Babej Associate Software Engineer | Red Hat | Identity Management RHCE | Brno Site | IRC: tbabej | freeipa.org
>From 2de4f0020a2a09b6328018652a49d8e4bf6c2c20 Mon Sep 17 00:00:00 2001 From: Tomas Babej <tba...@redhat.com> Date: Wed, 19 Nov 2014 12:00:07 +0100 Subject: [PATCH] baseldap: Handle missing parent objects properly in *-find commands The find_entries function in ipaldap does not differentiate between a LDAP search that returns error code 32 (No such object) and LDAP search returning error code 0 (Success), but returning no results. In both cases errors.NotFound is raised. In turn, LDAPSearch commands interpret NotFound exception as no results. To differentiate between the cases, a new error ContainerNotFound was added, which inherits from NotFound to preserve the compatibility with the new code. This error is raised by ipaldap.find_entries in case it is performing a search with onelevel or subtree scope, and the target dn does not exist. https://fedorahosted.org/freeipa/ticket/4659 --- ipalib/errors.py | 16 ++++++++++++++++ ipalib/plugins/baseldap.py | 2 ++ ipapython/ipaldap.py | 12 +++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ipalib/errors.py b/ipalib/errors.py index f0426583dae2982b661d8c6d1540fe4acea83cef..7436b5e4bce2c024ab7b686a94b6aa124ebb2840 100644 --- a/ipalib/errors.py +++ b/ipalib/errors.py @@ -1329,6 +1329,22 @@ class PosixGroupViolation(ExecutionError): errno = 4030 format = _('This is already a posix group and cannot be converted to external one') +class ContainerNotFound(NotFound): + """ + **4031** Raised when a container upon which a subtree or one-level search + is performed is not found. + + For example: + + >>> raise ContainerNotFound(reason='no such entry') + Traceback (most recent call last): + ... + ContainerNotFound: no such entry + + """ + + errno = 4031 + class BuiltinError(ExecutionError): """ **4100** Base class for builtin execution errors (*4100 - 4199*). diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py index 375441c0fd55efe70d5a6f5bed6700e618874082..67d0a08aed813f87798a657d6b3ab4a9497977ed 100644 --- a/ipalib/plugins/baseldap.py +++ b/ipalib/plugins/baseldap.py @@ -1995,6 +1995,8 @@ class LDAPSearch(BaseLDAPCommand, crud.Search): time_limit=options.get('timelimit', None), size_limit=options.get('sizelimit', None) ) + except errors.ContainerNotFound: + self.api.Object[self.obj.parent_object].handle_not_found(*args[:-1]) except errors.NotFound: (entries, truncated) = ([], False) diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py index 1702daa253d7eb568c27f66fda1810b4661656ad..4acd290e337b6544e85cca03226da8ae1c926c9c 100644 --- a/ipapython/ipaldap.py +++ b/ipapython/ipaldap.py @@ -1149,7 +1149,7 @@ class LDAPClient(object): self.conn = None @contextlib.contextmanager - def error_handler(self, arg_desc=None): + def error_handler(self, arg_desc=None, container_search=False): """Context manager that handles LDAPErrors """ try: @@ -1164,7 +1164,11 @@ class LDAPClient(object): info = "%s arguments: %s" % (info, arg_desc) raise except ldap.NO_SUCH_OBJECT: - raise errors.NotFound(reason=arg_desc or 'no such entry') + error_message = arg_desc or 'no such entry' + if container_search: + raise errors.ContainerNotFound(reason=error_message) + else: + raise errors.NotFound(reason=error_message) except ldap.ALREADY_EXISTS: raise errors.DuplicateEntry() except ldap.CONSTRAINT_VIOLATION: @@ -1472,8 +1476,10 @@ class LDAPClient(object): if page_size == 0: paged_search = False + search_in_container = scope in (ldap.SCOPE_SUBTREE, ldap.SCOPE_ONELEVEL) + # pass arguments to python-ldap - with self.error_handler(): + with self.error_handler(container_search=search_in_container): while True: if paged_search: sctrls = [SimplePagedResultsControl(0, page_size, cookie)] -- 1.9.3
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel