7
7
Notes:
8
8
9
9
The bound user needs read access to the attributes entryDN and entryCSN.
10
-
11
- This needs the following software:
12
- Python
13
- pyasn1 0.1.4+
14
- pyasn1-modules
15
- python-ldap 2.4.10+
16
10
"""
17
11
18
12
# Import modules from Python standard lib
19
- import shelve ,signal ,time ,sys ,logging
13
+ import logging
14
+ import shelve
15
+ import signal
16
+ import sys
17
+ import time
20
18
21
19
# Import the python-ldap modules
22
20
import ldap
25
23
from ldap .ldapobject import ReconnectLDAPObject
26
24
from ldap .syncrepl import SyncreplConsumer
27
25
26
+ logger = logging .getLogger ('syncrepl' )
27
+ logger .setLevel (logging .DEBUG )
28
+ logger .addHandler (logging .StreamHandler ())
28
29
29
30
# Global state
30
31
watcher_running = True
31
32
ldap_connection = False
32
33
33
34
34
- class SyncReplConsumer (ReconnectLDAPObject , SyncreplConsumer ):
35
+ class SyncReplClient (ReconnectLDAPObject , SyncreplConsumer ):
35
36
"""
36
- Syncrepl Consumer interface
37
+ Syncrepl Consumer Client
37
38
"""
38
39
39
40
def __init__ (self , db_path , * args , ** kwargs ):
40
41
# Initialise the LDAP Connection first
41
42
ldap .ldapobject .ReconnectLDAPObject .__init__ (self , * args , ** kwargs )
42
43
# Now prepare the data store
43
- self .__data = shelve .open (db_path , 'c' )
44
+ if db_path :
45
+ self .__data = shelve .open (db_path , 'c' )
46
+ else :
47
+ self .__data = dict ()
44
48
# We need this for later internal use
45
49
self .__presentUUIDs = dict ()
46
50
47
51
def close_db (self ):
48
- # Close the data store properly to avoid corruption
49
- self .__data .close ()
52
+ # Close the data store properly to avoid corruption
53
+ self .__data .close ()
50
54
51
55
def syncrepl_get_cookie (self ):
52
56
if 'cookie' in self .__data :
@@ -55,7 +59,8 @@ def syncrepl_get_cookie(self):
55
59
def syncrepl_set_cookie (self ,cookie ):
56
60
self .__data ['cookie' ] = cookie
57
61
58
- def syncrepl_entry (self ,dn ,attributes ,uuid ):
62
+ def syncrepl_entry (self , dn , attributes , uuid ):
63
+ logger .debug ('dn=%r attributes=%r uuid=%r' , dn , attributes , uuid )
59
64
# First we determine the type of change we have here
60
65
# (and store away the previous data for later if needed)
61
66
previous_attributes = dict ()
@@ -69,18 +74,18 @@ def syncrepl_entry(self,dn,attributes,uuid):
69
74
attributes ['dn' ] = dn
70
75
self .__data [uuid ] = attributes
71
76
# Debugging
72
- print 'Detected' , change_type , ' of entry: ' , dn
77
+ logger . debug ( 'Detected %s of entry %r ' , change_type , dn )
73
78
# If we have a cookie then this is not our first time being run,
74
79
# so it must be a change
75
80
if 'ldap_cookie' in self .__data :
76
- self .perform_application_sync (dn , attributes , previous_attributes )
81
+ self .perform_application_sync (dn , attributes , previous_attributes )
77
82
78
83
def syncrepl_delete (self ,uuids ):
79
84
# Make sure we know about the UUID being deleted, just in case...
80
85
uuids = [uuid for uuid in uuids if uuid in self .__data ]
81
86
# Delete all the UUID values we know of
82
87
for uuid in uuids :
83
- print 'Detected deletion of entry: ' , self .__data [uuid ]['dn' ]
88
+ logger . debug ( 'Detected deletion of entry %r ' , self .__data [uuid ]['dn' ])
84
89
del self .__data [uuid ]
85
90
86
91
def syncrepl_present (self ,uuids ,refreshDeletes = False ):
@@ -105,78 +110,80 @@ def syncrepl_present(self,uuids,refreshDeletes=False):
105
110
self .__presentUUIDs [uuid ] = True
106
111
107
112
def syncrepl_refreshdone (self ):
108
- print 'Initial synchronization is now done, persist phase begins'
113
+ logger . info ( 'Initial synchronization is now done, persist phase begins' )
109
114
110
115
def perform_application_sync (self ,dn ,attributes ,previous_attributes ):
111
- print 'Performing application sync for: ' , dn
116
+ logger . info ( 'Performing application sync for %r ' , dn )
112
117
return True
113
118
114
119
115
120
# Shutdown handler
116
121
def commenceShutdown (signum , stack ):
117
122
# Declare the needed global variables
118
123
global watcher_running , ldap_connection
119
- print 'Shutting down!'
124
+ logger . warn ( 'Shutting down!' )
120
125
121
126
# We are no longer running
122
127
watcher_running = False
123
128
124
129
# Tear down the server connection
125
- if ( ldap_connection ) :
126
- ldap_connection .close_db ()
127
- ldap_connection .unbind_s ()
128
- del ldap_connection
130
+ if ldap_connection :
131
+ ldap_connection .close_db ()
132
+ ldap_connection .unbind_s ()
133
+ del ldap_connection
129
134
130
135
# Shutdown
131
136
sys .exit (0 )
132
137
133
138
# Time to actually begin execution
134
139
# Install our signal handlers
135
- signal .signal (signal .SIGTERM ,commenceShutdown )
136
- signal .signal (signal .SIGINT ,commenceShutdown )
140
+ signal .signal (signal .SIGTERM , commenceShutdown )
141
+ signal .signal (signal .SIGINT , commenceShutdown )
137
142
138
143
139
144
try :
140
- ldap_url = ldapurl .LDAPUrl (sys .argv [1 ])
141
- database_path = sys .argv [2 ]
145
+ ldap_url = ldapurl .LDAPUrl (sys .argv [1 ])
146
+ database_path = sys .argv [2 ]
142
147
except IndexError ,e :
143
- print 'Usage:'
144
- print sys .argv [0 ], '<LDAP URL> <pathname of database>'
145
- print sys .argv [0 ], '\' ldap://127.0.0.1/cn=users,dc=test' \
146
- '?*' \
147
- '?sub' \
148
- '?(objectClass=*)' \
149
- '?bindname=uid=admin%2ccn=users%2cdc=test,' \
150
- 'X-BINDPW=password\' db.shelve'
148
+ print (
149
+ 'Usage:\n '
150
+ '{script_name} <LDAP URL> <pathname of database>\n '
151
+ '{script_name} "ldap://127.0.0.1/cn=users,dc=test'
152
+ '?*'
153
+ '?sub'
154
+ '?(objectClass=*)'
155
+ '?bindname=uid=admin%2ccn=users%2cdc=test,'
156
+ 'X-BINDPW=password" db.shelve'
157
+ ).format (script_name = sys .argv [0 ])
151
158
sys .exit (1 )
152
159
except ValueError ,e :
153
- print 'Error parsing command-line arguments:' ,str (e )
154
- sys .exit (1 )
160
+ print 'Error parsing command-line arguments:' , str (e )
161
+ sys .exit (1 )
155
162
156
163
while watcher_running :
157
- print 'Connecting to LDAP server now...'
164
+ logger . info ( 'Connecting to %s now...' , ldap_url . initializeUrl ())
158
165
# Prepare the LDAP server connection (triggers the connection as well)
159
- ldap_connection = SyncReplConsumer (database_path , ldap_url .initializeUrl ())
166
+ ldap_connection = SyncReplClient (database_path , ldap_url .initializeUrl ())
160
167
161
168
# Now we login to the LDAP server
162
169
try :
163
170
ldap_connection .simple_bind_s (ldap_url .who , ldap_url .cred )
164
- except ldap .INVALID_CREDENTIALS , e :
165
- print 'Login to LDAP server failed: ' , str ( e )
171
+ except ldap .INVALID_CREDENTIALS , err :
172
+ logger . error ( 'Login to LDAP server failed: %s ' , err )
166
173
sys .exit (1 )
167
174
except ldap .SERVER_DOWN :
168
- print 'LDAP server is down, going to retry.'
175
+ logger . warn ( 'LDAP server is down, going to retry.' )
169
176
time .sleep (5 )
170
177
continue
171
178
172
179
# Commence the syncing
173
- print 'Commencing sync process'
180
+ logger . debug ( 'Commencing sync process' )
174
181
ldap_search = ldap_connection .syncrepl_search (
175
- ldap_url .dn or '' ,
176
- ldap_url .scope or ldap .SCOPE_SUBTREE ,
177
- mode = 'refreshAndPersist' ,
178
- attrlist = ldap_url .attrs ,
179
- filterstr = ldap_url .filterstr or '(objectClass=*)'
182
+ ldap_url .dn or '' ,
183
+ ldap_url .scope or ldap .SCOPE_SUBTREE ,
184
+ mode = 'refreshAndPersist' ,
185
+ attrlist = ldap_url .attrs ,
186
+ filterstr = ldap_url .filterstr or '(objectClass=*)'
180
187
)
181
188
182
189
try :
@@ -185,10 +192,9 @@ def commenceShutdown(signum, stack):
185
192
except KeyboardInterrupt :
186
193
# User asked to exit
187
194
commenceShutdown (None , None )
188
- pass
189
- except Exception , e :
195
+ except Exception , err :
190
196
# Handle any exception
191
197
if watcher_running :
192
- print 'Encountered a problem, going to retry. Error:' , str (e )
198
+ logger .exception ('Unhandled exception, going to retry: %s' , err )
199
+ logger .info ('Going to retry after 5 secs' )
193
200
time .sleep (5 )
194
- pass
0 commit comments