Project migrated to https://gogs.zionetrix.net/bn8/check_syncrepl_extended
Benjamin Renard

Benjamin Renard commited on 2017-09-11 10:30:39
Showing 2 changed files, with 2 additions and 500 deletions.

... ...
@@ -1,95 +1,3 @@
1
-Script to check LDAP syncrepl replication state between two servers
2
-===================================================================
1
+This project have been migrated to :
3 2
 
4
-This script check LDAP syncrepl replication state between two servers.
5
-One server is consider as provider and the other as consumer.
6
-
7
-This script can check replication state with two method :
8
- - by the fisrt, entryCSN of all entries of LDAP directory will be
9
-   compare between two servers
10
- - by the second, all values of all atributes of all entries will
11
-   be compare between two servers.
12
-
13
-In all case, contextCSN of servers will be compare and entries not
14
-present in consumer or in provider will be notice. You can decide to
15
-disable contextCSN verification by using argument --no-check-contextCSN.
16
-
17
-This script is also able to "touch" LDAP object on provider to force
18
-synchronisation of this object. This mechanism consist to add '%%TOUCH%%'
19
-value to an attribute of this object and remove it just after. The
20
-touched attribute is specify by parameter --touch. Of course, couple of
21
-DN and password provided, must have write right on this attribute.
22
-
23
-If your prefer, you can use --replace-touch parameter to replace value
24
-of touched attribute instead of adding the touched value. Use-ful in
25
-case of single-value attribute.
26
-
27
-To use this script as Nagios plugin, use -n argument
28
-
29
-Requirement
30
------------
31
-
32
-A single couple of DN and password able to connect to both server 
33
-and without restriction to retrieve objects from servers.
34
-
35
-Usage
36
------
37
-
38
-  Usage: check_syncrepl_extended [options]
39
-  
40
-  Options:
41
-    --version             show program's version number and exit
42
-    -h, --help            show this help message and exit
43
-    -p PROVIDER, --provider=PROVIDER
44
-                          LDAP provider URI (example :
45
-                          ldaps://ldapmaster.foo:636)
46
-    -c CONSUMER, --consumer=CONSUMER
47
-                          LDAP consumer URI (example :
48
-                          ldaps://ldapslave.foo:636)
49
-    -D DN, --dn=DN        LDAP bind DN (example :
50
-                          uid=nagios,ou=sysaccounts,o=example
51
-    -P PWD, --pwd=PWD     LDAP bind password
52
-    -b BASEDN, --basedn=BASEDN
53
-                          LDAP base DN (example : o=example)
54
-    -f FILTER, --filter=FILTER
55
-                          LDAP filter (default : (objectClass=*))
56
-    -d, --debug           Debug mode
57
-    -n, --nagios          Nagios check plugin mode
58
-    -q, --quiet           Quiet mode
59
-    --no-check-certificate
60
-                          Don't check the server certificate (Default : False)
61
-    --no-check-contextCSN
62
-                          Don't check servers contextCSN (Default : False)
63
-    -a, --attributes      Check attributes values (Default : check only
64
-                          entryCSN)
65
-    --exclude-attributes=EXCL_ATTRS
66
-                          Don't check this attribut (only in attribute check
67
-                          mode)
68
-    --touch=TOUCH         Touch attribute giving in parameter to force resync a
69
-                          this LDAP object from provider. A value '%%TOUCH%%'
70
-                          will be add to this attribute and remove after. The
71
-                          user use to connect to the LDAP directory must have
72
-                          write permission on this attribute on each object.
73
-    --replace-touch       In touch mode, replace value instead of adding.
74
-
75
-
76
-Copyright
77
----------
78
-
79
-Copyright (c) 2013 Benjamin Renard 
80
-
81
-License
82
--------
83
-
84
-This program is free software; you can redistribute it and/or
85
-modify it under the terms of the GNU General Public License version 2
86
-as published by the Free Software Foundation.
87
-
88
-This program is distributed in the hope that it will be useful,
89
-but WITHOUT ANY WARRANTY; without even the implied warranty of
90
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
91
-GNU General Public License for more details.
92
-
93
-You should have received a copy of the GNU General Public License
94
-along with this program; if not, write to the Free Software
95
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
3
+https://gogs.zionetrix.net/bn8/check_syncrepl_extended
... ...
@@ -1,406 +0,0 @@
1
-#!/usr/bin/python
2
-
3
-#
4
-# Script to check LDAP syncrepl replication state between two servers.
5
-# One server is consider as provider and the other as consumer.
6
-#
7
-# This script can check replication state with two method :
8
-#  - by the fisrt, entryCSN of all entries of LDAP directory will be
9
-#    compare between two servers
10
-#  - by the second, all values of all atributes of all entries will
11
-#    be compare between two servers.
12
-#
13
-# In all case, contextCSN of servers will be compare and entries not
14
-# present in consumer or in provider will be notice. You can decide to
15
-# disable contextCSN verification by using argument --no-check-contextCSN.
16
-#
17
-# This script is also able to "touch" LDAP object on provider to force
18
-# synchronisation of this object. This mechanism consist to add '%%TOUCH%%'
19
-# value to an attribute of this object and remove it just after. The
20
-# touched attribute is specify by parameter --touch. Of course, couple of
21
-# DN and password provided, must have write right on this attribute.
22
-#
23
-# If your prefer, you can use --replace-touch parameter to replace value
24
-# of touched attribute instead of adding the touched value. Use-ful in
25
-# case of single-value attribute.
26
-#
27
-# This script could be use as Nagios plugin (-n argument)
28
-#
29
-# Requirement : 
30
-# A single couple of DN and password able to connect to both server 
31
-# and without restriction to retrieve objects from servers.
32
-#
33
-# Author : Benjamin Renard <brenard@easter-eggs.com>
34
-# Date : Mon, 10 Dec 2012 18:04:24 +0100
35
-# Source : http://git.zionetrix.net/check_syncrepl_extended
36
-#
37
-
38
-import ldap
39
-import ldap.modlist as modlist
40
-import logging
41
-import sys
42
-import getpass
43
-
44
-from optparse import OptionParser
45
-
46
-TOUCH_VALUE='%%TOUCH%%'
47
-
48
-parser = OptionParser(version="%prog version 1.0\n\nDate : Mon, 10 Dec 2012 18:04:24 +0100\nAuthor : Benjamin Renard <brenard@easter-eggs.com>\nSource : http://git.zionetrix.net/check_syncrepl_extended")
49
-
50
-parser.add_option(	"-p", "--provider",
51
-			dest="provider",
52
-			action="store",
53
-			type='string',
54
-			help="LDAP provider URI (example : ldaps://ldapmaster.foo:636)")
55
-
56
-parser.add_option(	"-c", "--consumer",
57
-			dest="consumer",
58
-			action="store",
59
-			type='string',
60
-			help="LDAP consumer URI (example : ldaps://ldapslave.foo:636)")
61
-
62
-parser.add_option(	"-T", "--starttls",
63
-			dest="starttls",
64
-			action="store_true",
65
-			help="Start TLS on LDAP provider/consumers connections",
66
-			default=False)
67
-
68
-parser.add_option(	"-D", "--dn",
69
-			dest="dn",
70
-			action="store",
71
-			type='string',
72
-			help="LDAP bind DN (example : uid=nagios,ou=sysaccounts,o=example")
73
-
74
-parser.add_option(	"-P", "--pwd",
75
-			dest="pwd",
76
-			action="store",
77
-			type='string',
78
-			help="LDAP bind password. Specify '-P -' to ask for a prompt.")
79
-
80
-parser.add_option(	"-b", "--basedn",
81
-			dest="basedn",
82
-			action="store",
83
-			type='string',
84
-			help="LDAP base DN (example : o=example)")
85
-
86
-parser.add_option(	"-f", "--filter",
87
-			dest="filter",
88
-			action="store",
89
-			type='string',
90
-			help="LDAP filter (default : (objectClass=*))",
91
-			default='(objectClass=*)')
92
-
93
-parser.add_option(	"-d", "--debug",
94
-			dest="debug",
95
-			action="store_true",
96
-			help="Debug mode",
97
-			default=False)
98
-
99
-parser.add_option(	"-n", "--nagios",
100
-			dest="nagios",
101
-			action="store_true",
102
-			help="Nagios check plugin mode",
103
-			default=False)
104
-
105
-parser.add_option(	"-q", "--quiet",
106
-			dest="quiet",
107
-			action="store_true",
108
-			help="Quiet mode",
109
-			default=False)
110
-
111
-parser.add_option(	"--no-check-certificate",
112
-			dest="nocheckcert",
113
-			action="store_true",
114
-			help="Don't check the server certificate (Default : False)",
115
-			default=False)
116
-
117
-parser.add_option(	"--no-check-contextCSN",
118
-			dest="nocheckcontextcsn",
119
-			action="store_true",
120
-			help="Don't check servers contextCSN (Default : False)",
121
-			default=False)
122
-
123
-parser.add_option(	"-a", "--attributes",
124
-			dest="attrs",
125
-			action="store_true",
126
-			help="Check attributes values (Default : check only entryCSN)",
127
-			default=False)
128
-
129
-parser.add_option(	"--exclude-attributes",
130
-			dest="excl_attrs",
131
-			action="store",
132
-			type='string',
133
-			help="Don't check this attribut (only in attribute check mode)",
134
-			default=None)
135
-
136
-parser.add_option(	"--touch",
137
-			dest="touch",
138
-			action="store",
139
-			type='string',
140
-			help="Touch attribute giving in parameter to force resync a this LDAP object from provider. A value '%s' will be add to this attribute and remove after. The user use to connect to the LDAP directory must have write permission on this attribute on each object." % TOUCH_VALUE,
141
-			default=None)
142
-
143
-parser.add_option(	"--replace-touch",
144
-			dest="replacetouch",
145
-			action="store_true",
146
-			help="In touch mode, replace value instead of adding.",
147
-			default=False)
148
-
149
-(options, args) = parser.parse_args()
150
-
151
-if not options.provider or not options.consumer:
152
-	print "You must provide provider and customer URI"
153
-	sys.exit(1)
154
-
155
-if not options.basedn:
156
-	print "You must provide base DN of connection to LDAP servers"
157
-	sys.exit(1)
158
-
159
-if options.touch and not options.attrs:
160
-	logging.info('Force option attrs on touch mode')
161
-	options.attrs=True
162
-
163
-if options.pwd == '-':
164
-	options.pwd=getpass.getpass()
165
-
166
-excl_attrs=[]
167
-if options.excl_attrs:
168
-	for ex in options.excl_attrs.split(','):
169
-		excl_attrs.append(ex.strip())
170
-
171
-FORMAT="%(asctime)s - %(levelname)s : %(message)s"
172
-
173
-if options.debug:
174
-	logging.basicConfig(level=logging.DEBUG,format=FORMAT)
175
-	ldap.set_option(ldap.OPT_DEBUG_LEVEL,0)
176
-	ldapmodule_trace_level = 1
177
-	ldapmodule_trace_file = sys.stderr
178
-elif options.nagios:
179
-	logging.basicConfig(level=logging.ERROR,format=FORMAT)
180
-elif options.quiet:
181
-	logging.basicConfig(level=logging.WARNING,format=FORMAT)
182
-else:
183
-	logging.basicConfig(level=logging.INFO,format=FORMAT)
184
-
185
-class LdapServer(object):
186
-
187
-	uri = ""
188
-	dn = ""
189
-	pwd = ""
190
-	start_tls = False
191
-
192
-	con = 0
193
-
194
-	def __init__(self,uri,dn,pwd, start_tls=False):
195
-		self.uri	= uri
196
-		self.dn		= dn
197
-		self.pwd	= pwd
198
-		self.start_tls	= start_tls
199
-
200
-	def connect(self):
201
-		if self.con == 0:
202
-			try:
203
-				con = ldap.initialize(self.uri)
204
-				con.protocol_version = ldap.VERSION3
205
-				if self.start_tls:
206
-					con.start_tls_s()
207
-				if self.dn:
208
-					con.simple_bind_s(self.dn,self.pwd)
209
-				self.con = con
210
-				return True
211
-			except ldap.LDAPError, e:
212
-				logging.error("LDAP Error : %s" % e)
213
-				return
214
-
215
-	def getContextCSN(self,basedn):
216
-		data=self.search(basedn,'(objectclass=*)',['contextCSN'])
217
-		if len(data)>0:
218
-			return data[0][0][1]['contextCSN'][0]
219
-		else:
220
-			return False
221
-
222
-	def search(self,basedn,filter,attrs):
223
-		res_id = self.con.search(basedn,ldap.SCOPE_SUBTREE,filter,attrs)
224
-		ret = []
225
-		while 1:
226
-			res_type, res_data = self.con.result(res_id,0)
227
-			if res_data == []:
228
-				break
229
-			else:
230
-				if res_type == ldap.RES_SEARCH_ENTRY:
231
-					ret.append(res_data)
232
-		return ret
233
-
234
-	def update_object(self,dn,old,new):
235
-		ldif = modlist.modifyModlist(old,new)
236
-		if ldif == []:
237
-			return True
238
-		try:
239
-			logging.debug('Update object %s : %s' % (dn,ldif))
240
-			self.con.modify_s(dn,ldif)
241
-			return True
242
-		except ldap.LDAPError, e:
243
-			logging.error('Error updating object %s : %s' % (dn,e))
244
-		return False
245
-
246
-	def get_attr(self,obj,attr):
247
-		if attr in obj[0][1]:
248
-			return obj[0][1][attr]
249
-		return []
250
-
251
-	def touch_object(self,dn,attr,orig_value):
252
-		if options.replacetouch:
253
-			new_value=[TOUCH_VALUE]
254
-		else:
255
-			new_value=list(orig_value)
256
-			new_value.append(TOUCH_VALUE)
257
-		try:
258
-			logging.info('Add value "%s" to attribute %s of object %s' % (TOUCH_VALUE,attr,dn))
259
-			if self.update_object(dn,{attr: orig_value}, {attr: new_value}):
260
-				logging.info('Remove value "%s" to attribute %s of object %s' % (TOUCH_VALUE,attr,dn))
261
-				self.update_object(dn,{attr: new_value}, {attr: orig_value})
262
-				return True
263
-		except ldap.LDAPError, e:
264
-			logging.error('Error touching object %s : %s' % (dn,e))
265
-		return False
266
-
267
-if options.nocheckcert:
268
-	ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_NEVER)
269
-
270
-servers=[options.provider,options.consumer]
271
-
272
-LdapServers={}
273
-LdapObjects={}
274
-LdapServersCSN={}
275
-
276
-for srv in servers:
277
-	logging.info('Connect to %s' % srv)
278
-	LdapServers[srv]=LdapServer(srv,options.dn,options.pwd,options.starttls)
279
-
280
-	if not LdapServers[srv].connect():
281
-		if options.nagios:
282
-			print "UNKWNON - Failed to connect to %s" % srv
283
-			sys.exit(3)
284
-		else:
285
-			sys.exit(1)
286
-
287
-	if not options.nocheckcontextcsn:
288
-		LdapServersCSN[srv]=LdapServers[srv].getContextCSN(options.basedn)
289
-		logging.info('ContextCSN of %s : %s' % (srv, LdapServersCSN[srv]))
290
-
291
-	logging.info('List objects from %s' % srv)
292
-	LdapObjects[srv]={}
293
-
294
-	if options.attrs:
295
-		for obj in LdapServers[srv].search(options.basedn,options.filter,[]):
296
-			logging.debug('Found on %s : %s' % (srv,obj[0][0]))
297
-			LdapObjects[srv][obj[0][0]]=obj[0][1]
298
-	else:
299
-		for obj in LdapServers[srv].search(options.basedn,options.filter,['entryCSN']):
300
-			logging.debug('Found on %s : %s / %s' % (srv,obj[0][0],obj[0][1]['entryCSN'][0]))
301
-			LdapObjects[srv][obj[0][0]]=obj[0][1]['entryCSN'][0]
302
-
303
-	logging.info('%s objects founds' % len(LdapObjects[srv]))
304
-
305
-
306
-not_found={}
307
-not_sync={}
308
-
309
-for srv in servers:
310
-	not_found[srv]=[]
311
-	not_sync[srv]=[]
312
-
313
-if options.attrs:
314
-	logging.info("Check if objects a are synchronized (by comparing attributes's values)")
315
-else:
316
-	logging.info('Check if objets are synchronized (by comparing entryCSN)')
317
-for obj in LdapObjects[options.provider]:
318
-	logging.debug('Check obj %s' % (obj))
319
-	for srv in LdapObjects:
320
-		if srv == options.provider:
321
-			continue
322
-		if obj in LdapObjects[srv]:
323
-			touch=False
324
-			if LdapObjects[options.provider][obj] != LdapObjects[srv][obj]:
325
-				if options.attrs:
326
-					attrs_list=[]
327
-					for attr in LdapObjects[options.provider][obj]:
328
-						if attr in excl_attrs:
329
-							continue
330
-						if attr not in LdapObjects[srv][obj]:
331
-							attrs_list.append(attr)
332
-							logging.debug("Obj %s not synchronized : %s not present on %s" % (obj,','.join(attrs_list),srv))
333
-							touch=True
334
-						else:
335
-							LdapObjects[srv][obj][attr].sort()
336
-							LdapObjects[options.provider][obj][attr].sort()
337
-							if LdapObjects[srv][obj][attr]!=LdapObjects[options.provider][obj][attr]:
338
-								attrs_list.append(attr)
339
-								logging.debug("Obj %s not synchronized : %s not same value(s)" % (obj,','.join(attrs_list)))
340
-								touch=True
341
-					if len(attrs_list)>0:
342
-						not_sync[srv].append("%s (%s)" % (obj,','.join(attrs_list)))
343
-				else:
344
-					logging.debug("Obj %s not synchronized : %s <-> %s" % (obj,LdapObjects[options.provider][obj],LdapObjects[srv][obj]))
345
-					not_sync[srv].append(obj)
346
-			if touch and options.touch:
347
-				orig_value=[]
348
-				if options.touch in LdapObjects[options.provider][obj]:
349
-					orig_value=LdapObjects[options.provider][obj][options.touch]
350
-				LdapServers[options.provider].touch_object(obj,options.touch,orig_value)
351
-		else:
352
-			logging.debug('Obj %s : not found on %s' % (obj,srv))
353
-			not_found[srv].append(obj)
354
-			if options.touch:
355
-				orig_value=[]
356
-				if options.touch in LdapObjects[options.provider][obj]:
357
-					orig_value=LdapObjects[options.provider][obj][options.touch]
358
-				LdapServers[options.provider].touch_object(obj,options.touch,orig_value)
359
-
360
-for obj in LdapObjects[options.consumer]:
361
-	logging.debug('Check obj %s of consumer' % obj)
362
-	if obj not in LdapObjects[options.provider]:
363
-		logging.debug('Obj %s : not found on provider' % obj)
364
-		not_found[options.provider].append(obj)
365
-
366
-if options.nagios:
367
-	errors=[]
368
-
369
-	if not options.nocheckcontextcsn:
370
-		for srv in LdapServersCSN:
371
-			if srv==options.provider:
372
-				continue
373
-			if LdapServersCSN[srv]!=LdapServersCSN[options.provider]:
374
-				errors.append('ContextCSN of %s not the same of provider' % srv)
375
-
376
-	if len(not_found[options.consumer])>0:
377
-		errors.append("%s not found object(s) on consumer" % len(not_found[options.consumer]))
378
-	if len(not_found[options.provider])>0:
379
-		errors.append("%s not found object(s) on provider" % len(not_found[options.provider]))
380
-	if len(not_sync[options.consumer])>0:
381
-		errors.append("%s not synchronized object(s) on consumer" % len(not_sync[options.consumer]))
382
-	if len(errors)>0:
383
-		print "CRITICAL : "+', '.join(errors)
384
-		sys.exit(2)
385
-	else:
386
-		print 'OK : consumer and provider are synchronized'
387
-		sys.exit(0)
388
-else:
389
-	noerror=True
390
-	for srv in servers:
391
-		if not options.nocheckcontextcsn:
392
-			if srv==options.provider:
393
-				continue
394
-			if LdapServersCSN[srv]!=LdapServersCSN[options.provider]:
395
-				logging.warning('ContextCSN of %s not the same of provider' % srv)
396
-				noerror=False
397
-
398
-		if len(not_found[srv])>0:
399
-			logging.warning('Not found objects on %s :\n  - %s' % (srv,'\n  - '.join(not_found[srv])))
400
-			noerror=False
401
-		if len(not_sync[srv])>0:
402
-			logging.warning('Not sync objects on %s : %s' % (srv,'\n  - '.join(not_sync[srv])))
403
-			noerror=False
404
-	
405
-	if noerror:
406
-		logging.info('No sync problem detected')
407 0