From: Alain S. <asp...@gm...> - 2007-01-26 21:39:40
|
When testing ReconnectLDAPObject I found a bug. The object doesn't reconnect after a main failure ! If I shutdown the ldap server and try a request, I get a ldap.SERVER_DOWN, this is correct. (this is what I call the main failure) But if I restart the server, and retry the same request (with the same object), I get an empty answer but no error! I'm expecting a correct answer or an error (exception)! I have a full script that show the problem at the end. It look the object is in an incoherent state after the main failure, in fact in an unauthenticated state ! I thing this is a problem with libldap or openldap, not with python code. I thing the main probleme is here ! Look ! l=ldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl()) l.simple_bind_s('cn=nobody,cn=internal,dc=asxnet,dc=loc', '***********') print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(objectClass=*)") works and return all object anonymous can get, but l=ldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl()) print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(objectClass=*)") this work too ! And don't give any error while their is no bind ! work like if l.simple_bind_s('', '') where used just before the search ! I wrote a patch but this is only a workaround that detect the main failure, set a flag and force a reconnect before any request if the flag is set. Here is the output of my test case I use a modified python-ldap, that include the patch posted in my previous post that enable reconnect to work with whoami_s() -- without debuging -- OpenPKG: stop: openldap. OpenPKG: start: openldap. Connected whoami dn:cn=nobody,cn=internal,dc=asxnet,dc=loc OpenPKG: stop: openldap. OpenPKG: start: openldap. whoami dn:cn=nobody,cn=internal,dc=asxnet,dc=loc reconnect ok OpenPKG: stop: openldap. ok: ldap.SERVER_DOWN, server is realy down OpenPKG: start: openldap. whoami It look i'am connected, but like anonymous -- with debuging -- OpenPKG: stop: openldap. OpenPKG: start: openldap. *** ldap://localhost:389 - ReconnectLDAPObject.set_option ((17, 3),{}) *** ldap://localhost:389 - ReconnectLDAPObject.simple_bind (('cn=nobody,cn=internal,dc=asxnet,dc=loc', 'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc', None, None),{}) *** ldap://localhost:389 - ReconnectLDAPObject.result3 ((1, 1, -1),{}) Connected *** ldap://localhost:389 - ReconnectLDAPObject.whoami_s ((None, None),{}) whoami dn:cn=nobody,cn=internal,dc=asxnet,dc=loc OpenPKG: stop: openldap. OpenPKG: start: openldap. *** ldap://localhost:389 - ReconnectLDAPObject.whoami_s ((None, None),{}) *** Try 1. reconnect to ldap://localhost:389... *** ldap://localhost:389 - ReconnectLDAPObject.set_option ((17, 3),{}) *** ldap://localhost:389 - ReconnectLDAPObject.simple_bind (('cn=nobody,cn=internal,dc=asxnet,dc=loc', 'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc', None, None),{}) *** ldap://localhost:389 - ReconnectLDAPObject.result3 ((1, 1, -1),{}) *** 1. reconnect to ldap://localhost:389 successful, last operation will be repeated *** ldap://localhost:389 - ReconnectLDAPObject.whoami_s ((None, None),{}) whoami dn:cn=nobody,cn=internal,dc=asxnet,dc=loc reconnect ok OpenPKG: stop: openldap. *** ldap://localhost:389 - ReconnectLDAPObject.whoami_s ((None, None),{}) *** Try 1. reconnect to ldap://localhost:389... *** ldap://localhost:389 - ReconnectLDAPObject.set_option ((17, 3),{}) *** ldap://localhost:389 - ReconnectLDAPObject.simple_bind (('cn=nobody,cn=internal,dc=asxnet,dc=loc', 'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc', None, None),{}) *** 1. reconnect to ldap://localhost:389 failed ok: ldap.SERVER_DOWN, server is realy down OpenPKG: start: openldap. *** ldap://localhost:389 - ReconnectLDAPObject.whoami_s ((None, None),{}) whoami It look i'am connected, but like anonymous ---- and finaly my test case ---- import sys, os, time import ldap, ldapurl host='localhost' port=389 who='cn=nobody,cn=internal,dc=asxnet,dc=loc' cred='iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' dn='dc=asxnet,dc=loc' def ldap_service(action): os.system('/kolab/bin/openpkg rc openldap %s' % action) if action.endswith('start'): time.sleep(1) def check_connection(): whoami=l.whoami_s() print 'whoami', whoami # this search dont give any result as anonymous, but well if loggged as nobody #result=l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(member=cn=domain.maintainer mydomain.loc,cn=internal,dc=asxnet,dc=loc)") #print 'search', result ldap_url=ldapurl.LDAPUrl('ldap://%s:%d/%s' % (host, port, dn)) ldap_url.applyDefaults({ 'who': who, 'cred' : cred, }) # to be sure the server is up ldap_service('stop') ldap_service('start') l=ldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl(), 1) # l=ldap.ldapobject.LDAPObject(ldap_url.initializeUrl()) l.simple_bind_s(ldap_url.who, ldap_url.cred) print 'Connected' check_connection() ldap_service('stop') ldap_service('start') try: check_connection() except ldap.SERVER_DOWN: print "Error: ldap.SERVER_DOWN !" else: print "reconnect ok" ldap_service('stop') try: check_connection() except ldap.SERVER_DOWN: print "ok: ldap.SERVER_DOWN, server is realy down" ldap_service('start') check_connection() print "It look i'am connected, but like anonymous" import sys, os, time import ldap, ldapurl host='localhost' port=389 who='cn=nobody,cn=internal,dc=asxnet,dc=loc' cred='iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' dn='dc=asxnet,dc=loc' def ldap_service(action): os.system('/kolab/bin/openpkg rc openldap %s' % action) if action.endswith('start'): time.sleep(1) def check_connection(): #print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(member=cn=domain.maintainer mydomain.loc,cn=internal,dc=asxnet,dc=loc)") print 'whoami', l.whoami_s() ldap_url=ldapurl.LDAPUrl('ldap://%s:%d/%s' % (host, port, dn)) ldap_url.applyDefaults({ 'who': who, 'cred' : cred, }) ldap_service('stop') ldap_service('start') l=ldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl()) # l=ldap.ldapobject.LDAPObject(ldap_url.initializeUrl()) l.simple_bind_s(ldap_url.who, ldap_url.cred) print 'Connected' check_connection() ldap_service('stop') ldap_service('start') try: check_connection() except ldap.SERVER_DOWN: print "Error: ldap.SERVER_DOWN !" ldap_service('stop') try: check_connection() except ldap.SERVER_DOWN: print "Ok: ldap.SERVER_DOWN" ldap_service('start') check_connection() ANY Comments ? -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-01-26 22:44:34
|
Alain Spineux wrote: > When testing ReconnectLDAPObject I found a bug. > The object doesn't reconnect after a main failure ! > [..] > I thing the main probleme is here ! > Look ! Yes, I can reproduce your observation. Thanks for pointing it out. > l=ldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl()) > print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(objectClass=*)") > > this work too ! And don't give any error while their is no bind ! > work like if l.simple_bind_s('', '') where used just before the search ! Yes, this works as intended in LDAPv3. In opposite to LDAPv2 you MAY send a LDAP request without prior bind request. > I wrote a patch but this is only a workaround that detect the main > failure, set a flag and force a reconnect before any request if the > flag is set. Where's the patch? Can't figure out why it does not send the formerly sent bind request. It has all the data around. And if you take the server down it will re-send the bind request. Ciao, Michael. |
From: Alain S. <asp...@gm...> - 2007-01-26 23:23:02
|
On 1/26/07, Michael Str=F6der <mi...@st...> wrote: > Alain Spineux wrote: > > When testing ReconnectLDAPObject I found a bug. > > The object doesn't reconnect after a main failure ! > > [..] > > I thing the main probleme is here ! > > Look ! > > Yes, I can reproduce your observation. Thanks for pointing it out. Don't forget we are on the same boat Captain ! :-) > > > l=3Dldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl()) > > print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(objectCla= ss=3D*)") > > > > this work too ! And don't give any error while their is no bind ! > > work like if l.simple_bind_s('', '') where used just before the search = ! > > Yes, this works as intended in LDAPv3. In opposite to LDAPv2 you MAY > send a LDAP request without prior bind request. > > > I wrote a patch but this is only a workaround that detect the main > > failure, set a flag and force a reconnect before any request if the > > flag is set. > > Where's the patch? This is still only a workin "draft" I need to reread it's logic, anyway I add it at the end > Can't figure out why it does not send the formerly > sent bind request. It has all the data around. And if you take the > server down it will re-send the bind request. The trick is it doesn't try to reconnect AFTER the main failure (or BEFORE the next statement) ! Because the first try (of the next ldap statement) doesn't generate any error, it doesn't try to reconnect and then give the answer as is ! But this is the answer it got like an unauthenticated user ! Look, this is the tcpdump of the last statement ! 00:14:21.109514 IP 127.0.0.1.36250 > 127.0.0.1.ldap: S 1795648490:1795648490(0) win 00:14:21.110352 IP 127.0.0.1.ldap > 127.0.0.1.36250: S 1793421325:1793421325(0) ack 1795648491 win 32768 <mss 16396,sackOK,timestamp 516494160 516494159,nop,wscale 7> 00:14:21.110430 IP 127.0.0.1.36250 > 127.0.0.1.ldap: . ack 1 win 257 <nop,nop,timestamp 516494160 516494160> You can identify the well known 3-way handshaking ! This is a new connectio= n ! I thing libldap open a new connection, but libldap dont store anything about the credential and then cannot authenticate with the good user ! I will try to reproduce this in C with libc Here is the patch (including my whoami_s() ) *** ldapobject.py.disconnet Fri Jan 26 22:22:57 2007 --- ldapobject.py.orig Fri Jan 26 13:42:59 2007 *************** *** 678,684 **** self._retry_delay =3D retry_delay self._start_tls =3D 0 self._reconnects_done =3D 0L - self._disconnected=3DTrue def __getstate__(self): """return data representation for pickled object""" --- 678,683 ---- *************** *** 723,730 **** self.start_tls_s() # Repeat last simple or SASL bind self._apply_last_bind() ! except Exception, e: ! self._disconnected=3DTrue if __debug__ and self._trace_level>=3D1: self._trace_file.write('*** %d. reconnect to %s failed\n' % ( self._retry_max-reconnect_counter+1,uri --- 722,728 ---- self.start_tls_s() # Repeat last simple or SASL bind self._apply_last_bind() ! except: if __debug__ and self._trace_level>=3D1: self._trace_file.write('*** %d. reconnect to %s failed\n' % ( self._retry_max-reconnect_counter+1,uri *************** *** 736,742 **** self._trace_file.write('=3D> delay %s...\n' % (self._retry_dela= y)) time.sleep(self._retry_delay) else: - self._disconnected=3DFalse if __debug__ and self._trace_level>=3D1: self._trace_file.write('*** %d. reconnect to %s successful, last operation will be repeated\n' % ( self._retry_max-reconnect_counter+1,uri --- 734,739 ---- *************** *** 745,762 **** break def _apply_method_s(self,func,*args,**kwargs): ! if self._disconnected: self.reconnect(self._uri) # Re-try last operation return func(self,*args,**kwargs) - else: - try: - return func(self,*args,**kwargs) - except ldap.SERVER_DOWN: - # Reconnect - self.reconnect(self._uri) - # Re-try last operation - return func(self,*args,**kwargs) def set_option(self,option,invalue): self._options[option] =3D invalue --- 742,754 ---- break def _apply_method_s(self,func,*args,**kwargs): ! try: ! return func(self,*args,**kwargs) ! except ldap.SERVER_DOWN: ! # Reconnect self.reconnect(self._uri) # Re-try last operation return func(self,*args,**kwargs) def set_option(self,option,invalue): self._options[option] =3D invalue *************** *** 764,772 **** def simple_bind_s(self,*args,**kwargs): self._last_bind =3D (self.simple_bind_s,args,kwargs) ! result=3DSimpleLDAPObject.simple_bind_s(self,*args,**kwargs) ! self._disconnected=3DFalse ! return result def start_tls_s(self): res =3D SimpleLDAPObject.start_tls_s(self) --- 756,762 ---- def simple_bind_s(self,*args,**kwargs): self._last_bind =3D (self.simple_bind_s,args,kwargs) ! return SimpleLDAPObject.simple_bind_s(self,*args,**kwargs) def start_tls_s(self): res =3D SimpleLDAPObject.start_tls_s(self) *************** *** 778,786 **** sasl_interactive_bind_s(who, auth) -> None """ self._last_bind =3D (self.sasl_interactive_bind_s,args,kwargs) ! result=3DSimpleLDAPObject.sasl_interactive_bind_s(self,*args,**kwargs= ) ! self._disconnected=3DFalse ! return result def add_ext_s(self,*args,**kwargs): return self._apply_method_s(SimpleLDAPObject.add_ext_s,*args,**kwargs= ) --- 768,774 ---- sasl_interactive_bind_s(who, auth) -> None """ self._last_bind =3D (self.sasl_interactive_bind_s,args,kwargs) ! return SimpleLDAPObject.sasl_interactive_bind_s(self,*args,**kwargs) def add_ext_s(self,*args,**kwargs): return self._apply_method_s(SimpleLDAPObject.add_ext_s,*args,**kwargs= ) *************** *** 800,808 **** def search_ext_s(self,*args,**kwargs): return self._apply_method_s(SimpleLDAPObject.search_ext_s,*args,**kwa= rgs) - def whoami_s(self,*args,**kwargs): - return self._apply_method_s(SimpleLDAPObject.whoami_s,*args,**kwargs) - class SmartLDAPObject(ReconnectLDAPObject): """ --- 788,793 ---- -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-01-27 00:40:13
|
Alain Spineux wrote: >> >> Where's the patch? > This is still only a workin "draft" I need to reread it's logic, > anyway I add it at the end Got your point now. But still I don't find an elegant solution without having to handle a 'disconnected' flag in several methods. > I thing libldap open a new connection, but libldap dont store anything > about the credential and then cannot authenticate with the good user ! > I will try to reproduce this in C with libc Yes, it's a bug in ReconnectLDAPObject. It doesn't have anything to do with libldap. Ciao, Michael. |
From: Alain S. <asp...@gm...> - 2007-01-27 00:57:49
|
Yes I got it ! The problem is the failed statement has initiated a new connection (when the server is down) calling initialize (that doesn't fail) and bind that fail but is in a try: except: block in ReconnectLDAPObject.reconnect() ! Then the server restart and the next statement get advantages of the work done initialize # first stop the service ldap_service('stop') # initiate a connection l=3Dldap.initialize(ldap_url.initializeUrl()) # I dont use ReconnectLDAPObj= ect ! try: l.simple_bind_s(ldap_url.who, ldap_url.cred) except ldap.SERVER_DOWN: pass # bind fail like in ReconnectLDAPObject.reconnect() ldap_service('start') check_connection() # that return an empty string The probleme is initialize don't initialize any connection ! from "man 3 ldap" : The basic interaction is as follows. A session handle is creat= ed using ldap_initialize(3) and set the protocol version to 3 by calli= ng ldap_set_option(3). The underlying session is established first ope= r- ation is issued. This would generally be a Start TLS or Bind oper= a- tion. The problem is that the first operation after Initialize will never put the connection into failing state when server is down! The problem is probably into libldap into the "auto connect at first operation" like described into man 3 ldap This let us do something like l=3Dldap.initialize(ldap_url.initializeUrl()) # I dont use ReconnectLDAPObj= ect ! while True: try: l.simple_bind_s(ldap_url.who, ldap_url.cred) except ldap.SERVER_DOWN: time.sleep(1) else: break print 'Connected' I don't know if this is a feature or a bug into libldap ! Then the logic of my patch look to be the good one. I still need to verify it once more. I go to sleep now On 1/26/07, Michael Str=F6der <mi...@st...> wrote: > Alain Spineux wrote: > > When testing ReconnectLDAPObject I found a bug. > > The object doesn't reconnect after a main failure ! > > [..] > > I thing the main probleme is here ! > > Look ! > > Yes, I can reproduce your observation. Thanks for pointing it out. > > > l=3Dldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl()) > > print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(objectCla= ss=3D*)") > > > > this work too ! And don't give any error while their is no bind ! > > work like if l.simple_bind_s('', '') where used just before the search = ! > > Yes, this works as intended in LDAPv3. In opposite to LDAPv2 you MAY > send a LDAP request without prior bind request. > > > I wrote a patch but this is only a workaround that detect the main > > failure, set a flag and force a reconnect before any request if the > > flag is set. > > Where's the patch? Can't figure out why it does not send the formerly > sent bind request. It has all the data around. And if you take the > server down it will re-send the bind request. > > Ciao, Michael. > --=20 -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-01-27 01:01:24
|
Alain Spineux wrote: > > The problem is the failed statement has initiated a new connection > (when the server is down) > calling initialize (that doesn't fail) and bind that fail but is in a > try: except: block in ReconnectLDAPObject.reconnect() ! > Then the server restart and the next statement get advantages of the > work done initialize Yes. Inspired by you mentioning libldap I remembered that unbind_s() should be called when handling ldap.SERVER_DOWN exception to completely drop the whole connection context. Please test the version I've committed some minutes ago. Thanks again. Ciao, Michael. |
From: Alain S. <asp...@gm...> - 2007-01-27 11:59:58
|
Yes, we did it ! My test case is working with your CVS ! I put it at the end. And what about the idea to put the try: except ldap.SERVER_DOWN,e: SimpleLDAPObject.unbind_s(self) in the function _ldap_call too ? This will correct also SimpleLDAPObject ? import sys, os, time import ldap, ldapurl host=3D'localhost' port=3D389 who=3D'cn=3Dnobody,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc' cred=3D'iMmTWz5pJ+lwY7i6M/BU61ngo1aBLyqQhRrrKbEc' dn=3D'dc=3Dasxnet,dc=3Dloc' def ldap_service(action): os.system('/kolab/bin/openpkg rc openldap %s' % action) if action.endswith('start'): time.sleep(1) def check_connection(): whoami=3Dl.whoami_s() print 'whoami', whoami # this search dont give any result as anonymous, but well if loggged as nobody #result=3Dl.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(member=3Dcn=3Ddomain.maintainer mydomain.loc,cn=3Dinternal,dc=3Dasxnet,dc=3Dloc)") #print 'search', result ldap_url=3Dldapurl.LDAPUrl('ldap://%s:%d/%s' % (host, port, dn)) ldap_url.applyDefaults({ 'who': who, 'cred' : cred, }) # to be sure the server is up ldap_service('stop') ldap_service('start') l=3Dldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl(),1) # I dont use ReconnectLDAPObject ! l.simple_bind_s(ldap_url.who, ldap_url.cred) check_connection() print 'Wait 120s' time.sleep(120) check_connection() print 'restart service' ldap_service('stop') ldap_service('start') check_connection() print 'stop service' ldap_service('stop') try: check_connection() except ldap.SERVER_DOWN: print 'check failed, OK' print 'restart service' ldap_service('start') check_connection() On 1/27/07, Michael Str=F6der <mi...@st...> wrote: > Alain Spineux wrote: > > > > The problem is the failed statement has initiated a new connection > > (when the server is down) > > calling initialize (that doesn't fail) and bind that fail but is in a > > try: except: block in ReconnectLDAPObject.reconnect() ! > > Then the server restart and the next statement get advantages of the > > work done initialize > > Yes. Inspired by you mentioning libldap I remembered that unbind_s() > should be called when handling ldap.SERVER_DOWN exception to completely > drop the whole connection context. > > Please test the version I've committed some minutes ago. > Thanks again. > > Ciao, Michael. > --=20 -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-01-27 20:53:03
|
On 12:59:58 pm 2007-01-27 "Alain Spineux" <asp...@gm...> wrote: > > And what about the idea to put the > > try: > except ldap.SERVER_DOWN,e: > SimpleLDAPObject.unbind_s(self) > > in the function _ldap_call too ? > This will correct also SimpleLDAPObject ? There is nothing wrong with SimpleLDAPObject. The application is supposed to catch and handle ldap.SERVER_DOWN. Additionally SimpleLDAPObject and ReconnectLDAPObject shall behave in the same way. And IMO they do now. Ciao, Michael. |
From: Alain S. <asp...@gm...> - 2007-01-28 01:06:47
|
This is a good point of view! Anyway I try my _LAST_ arguments. Python is a language made to help and facilitate the developer work : - the developer dont need to test the result of any function, python (or the library) raise an exception if something is wrong. - the developer dont need to worry about the memory allocation, the garbage collector do it for him. - the developer dont need to close a file, the system do it for him when the object is released - the developer don't need to worry for long living LDAP connection, ReconnectLDAPObject auto reconnect automatically for him :-) - python-ldap is also thread safe ..... Then why does the developer have to encapsulate any ldap statement into a try: except ldap.SERVER_DOWN,e: SimpleLDAPObject.unbind_s(self) whereas=09the library can do it for him Anyway we made a good job ! Tanks for your support. On 1/27/07, "Michael Str=F6der" <mi...@st...> wrote: > On 12:59:58 pm 2007-01-27 "Alain Spineux" <asp...@gm...> wrote: > > > > And what about the idea to put the > > > > try: > > except ldap.SERVER_DOWN,e: > > SimpleLDAPObject.unbind_s(self) > > > > in the function _ldap_call too ? > > This will correct also SimpleLDAPObject ? > > There is nothing wrong with SimpleLDAPObject. The application is supposed > to catch and handle ldap.SERVER_DOWN. Additionally SimpleLDAPObject and > ReconnectLDAPObject shall behave in the same way. And IMO they do now. > > Ciao, Michael. > > --=20 -- Alain Spineux aspineux gmail com May the sources be with you |
From: <mi...@st...> - 2007-01-29 11:10:40
|
Alain Spineux wrote: > > Python is a language made to help and facilitate the developer work : > - the developer dont need to test the result of any function, python > (or the library) raise an exception if something is wrong. > - the developer dont need to worry about the memory allocation, the > garbage collector do it for him. > - the developer dont need to close a file, the system do it for him > when the object is released > - the developer don't need to worry for long living LDAP connection, > ReconnectLDAPObject auto reconnect automatically for him :-) > - python-ldap is also thread safe ..... Your list rather arguments for adding SimpleLDAPObject.__del__() if not implemented yet (I have to look at it). > Then why does the developer have to encapsulate any ldap statement into a > > try: > except ldap.SERVER_DOWN,e: > SimpleLDAPObject.unbind_s(self) Because in case of ldap.SERVER_DOWN the application might have some means for fail-over, smart error handling or similar. python-ldap is rather low-level. I expect application developers to wrap something around SimpleLDAPObject which better suits there needs. And I'd like to avoid breaking existing code. Calling unbind_s() twice raises ldap.LDAPError: LDAP connection invalid Do you have an overview how other database modules handle such cases? Ciao, Michael. |
From: Alain S. <asp...@gm...> - 2007-01-29 14:27:58
|
Convinced :-) Best regards. On 1/29/07, Michael Str=F6der <mi...@st...> wrote: > Alain Spineux wrote: > > > > Python is a language made to help and facilitate the developer work : > > - the developer dont need to test the result of any function, python > > (or the library) raise an exception if something is wrong. > > - the developer dont need to worry about the memory allocation, the > > garbage collector do it for him. > > - the developer dont need to close a file, the system do it for him > > when the object is released > > - the developer don't need to worry for long living LDAP connection, > > ReconnectLDAPObject auto reconnect automatically for him :-) > > - python-ldap is also thread safe ..... > > Your list rather arguments for adding SimpleLDAPObject.__del__() if not > implemented yet (I have to look at it). > > > Then why does the developer have to encapsulate any ldap statement into= a > > > > try: > > except ldap.SERVER_DOWN,e: > > SimpleLDAPObject.unbind_s(self) > > Because in case of ldap.SERVER_DOWN the application might have some > means for fail-over, smart error handling or similar. python-ldap is > rather low-level. I expect application developers to wrap something > around SimpleLDAPObject which better suits there needs. > > And I'd like to avoid breaking existing code. Calling unbind_s() twice > raises > ldap.LDAPError: LDAP connection invalid > > Do you have an overview how other database modules handle such cases? > > Ciao, Michael. > --=20 -- Alain Spineux aspineux gmail com May the sources be with you |