Bonjour,

J'ai un problème de blocage en créant des threads via l'api eventlet.
En effet, je veux exécuter un programme qui fait la synchronisation avec une base de donnée ldap parallèlement avec un autre programme.
Mais, en lançant mon script l'exécution se bloque sur la fonction faisant la synchronisation ldap et empêche l'appel des autres fonctions via eventlet.
Je tiens à vous informer que le problème n'est pas reproductible en lançant des thread avec l'api thread !!!
Mais, j'ai une contrainte forte d'utiliser eventlet pour mon cas.

Voici mon code ci-dessous. L’exécution de ce script requière une configuration du serveur et du client ldap.
Pour résumer, je me demande comment dois-je utiliser l'api eventlet pour avoir un comportement identique à celui de l'api thread afin d'éviter ce blocage ?

D'avance merci.
Cordialement.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
 
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
This script implements a syncrepl consumer which syncs data from an OpenLDAP
server to a local (shelve) database.
Notes:
The bound user needs read access to the attributes entryDN and entryCSN.
This needs the following software:
Python
pyasn1 0.1.4+
pyasn1-modules
python-ldap 2.4.10+
"""
 
# Import the python-ldap modules
import ldap,ldapurl
# Import specific classes from python-ldap
from ldap.ldapobject import ReconnectLDAPObject
from ldap.syncrepl import SyncreplConsumer
 
# Import modules from Python standard lib
import shelve,signal,time,sys,logging
import eventlet
#import thread
eventlet.monkey_patch()
 
# Global state
watcher_running = True
ldap_connection = False
 
 
 
class SyncReplConsumer(ReconnectLDAPObject,SyncreplConsumer):
    """
    Syncrepl Consumer interface
    """
    def __init__(self,db_path,*args,**kwargs):
        # Initialise the LDAP Connection first
        ldap.ldapobject.ReconnectLDAPObject.__init__(self, *args, **kwargs)
        # Now prepare the data store
        self.__data = shelve.open(db_path, 'c')
        # We need this for later internal use
        self.__presentUUIDs = dict()
 
    def __del__(self):
            # Close the data store properly to avoid corruption
            self.__data.close()
 
    def syncrepl_get_cookie(self):
        if 'cookie' in self.__data:
            return self.__data['cookie']
 
    def syncrepl_set_cookie(self,cookie):
        self.__data['cookie'] = cookie
 
    def syncrepl_entry(self,dn,attributes,uuid):
 
        # First we determine the type of change we have here (and store away the previous data for later if needed)
        previous_attributes = dict()
        if uuid in self.__data:
            change_type = 'modify'
            previous_attributes = self.__data[uuid]
        else:
            change_type = 'add'
        # Now we store our knowledge of the existence of this entry (including the DN as an attribute for convenience)
        attributes['dn'] = dn
        self.__data[uuid] = attributes
        # Debugging
        print 'Detected', change_type, 'of entry:', dn
        # If we have a cookie then this is not our first time being run, so it must be a change
        if 'ldap_cookie' in self.__data:
                self.perform_application_sync(dn, attributes, previous_attributes)
 
    def syncrepl_delete(self,uuids):
        # Make sure we know about the UUID being deleted, just in case...
        uuids = [uuid for uuid in uuids if uuid in self.__data]
        # Delete all the UUID values we know of
        for uuid in uuids:
            print 'Detected deletion of entry:', self.__data[uuid]['dn']
            del self.__data[uuid]
 
    def syncrepl_present(self,uuids,refreshDeletes=False):
        # If we have not been given any UUID values, then we have recieved all the present controls...
        if uuids is None:
            # We only do things if refreshDeletes is false as the syncrepl extension will call syncrepl_delete instead when it detects a delete notice
            if refreshDeletes is False:
                deletedEntries = [uuid for uuid in self.__data.keys() if uuid not in self.__presentUUIDs and uuid != 'ldap_cookie']
                self.syncrepl_delete( deletedEntries )
            # Phase is now completed, reset the list
            self.__presentUUIDs = {}
        else:
            # Note down all the UUIDs we have been sent
            for uuid in uuids:
                    self.__presentUUIDs[uuid] = True
 
    def perform_application_sync(self,dn,attributes,previous_attributes):
        print 'Performing application sync for:', dn
        return True
 
 
# Shutdown handler
#def commenceShutdown(signum, stack):
def commenceShutdown():
    # Declare the needed global variables
    global watcher_running, ldap_connection
    print 'Shutting down!'
 
    # We are no longer running
    watcher_running = False
 
    # Tear down the server connection
    if( ldap_connection ):
            del ldap_connection
 
    # Shutdown
    sys.exit(0)
 
def mainOfSyncrepl(threadName):
     # Time to actually begin execution
     # Install our signal handlers
#     signal.signal(signal.SIGTERM,commenceShutdown)
#     signal.signal(signal.SIGINT,commenceShutdown)
     try:
       ldap_url = ldapurl.LDAPUrl('ldap://localhost/dc=exemple,dc=org?*?sub?(objectClass=*)?bindname=cn=admin%2cdc=test%2cdc=com,X-BINDPW=myPassword')#ldapurl.LDAPUrl(sys.argv[1])
     #  ldap_url = ldapurl.LDAPUrl(link)
       database_path = 'test.com'#sys.argv[2]
     #  database_path = pathName
     except IndexError,e:
       print 'Usage: syncrepl-client.py <LDAP URL> <pathname of database>'
       sys.exit(1)
     except ValueError,e:
       print 'Error parsing command-line arguments:',str(e)
       sys.exit(1)
 
     while watcher_running:
         print 'Connecting to LDAP server now...'
         # Prepare the LDAP server connection (triggers the connection as well)
         ldap_connection = SyncReplConsumer(database_path,ldap_url.initializeUrl())
 
         # Now we login to the LDAP server
         try:
             ldap_connection.simple_bind_s(ldap_url.who,ldap_url.cred)
         except ldap.INVALID_CREDENTIALS, e:
             print 'Login to LDAP server failed: ', str(e)
             sys.exit(1)
         except ldap.SERVER_DOWN:
             continue
 
         # Commence the syncing
         print 'Commencing sync process'
         ldap_search = ldap_connection.syncrepl_search(
           ldap_url.dn or '',
           ldap_url.scope or ldap.SCOPE_SUBTREE,
           mode = 'refreshAndPersist',
           filterstr = ldap_url.filterstr or '(objectClass=*)')
         print 'After syncrepl_search.'
         try:
             while ldap_connection.syncrepl_poll( all = 1, msgid = ldap_search):
                  pass
         except KeyboardInterrupt:
          # User asked to exit
             commenceShutdown()
             pass
         except Exception, e:
          # Handle any exception
             if watcher_running:
                 print 'Encountered a problem, going to retry. Error:', str(e)
#              time.sleep(5)
             pass
 
# Define a function for the 2nd thread
def print_time(ThreadName):
     count = 0
     delay = 3
     while 1:#count < 5:
         count += 1
         print "%s: %s" % (ThreadName, time.ctime(time.time()) )
         eventlet.sleep(delay)
 
 
 
print 'Before call threads'
 
evt1 = eventlet.spawn(mainOfSyncrepl, "Thread-1",)
evt2 = eventlet.spawn(print_time, "Thread-2",)
evt3 = eventlet.spawn(print_time, "Thread-3",)
 
print 'After call threads'
 
evt1.wait()
evt2.wait()
evt3.wait()
 
print 'After wait'