View | Details | Raw Unified | Return to bug 30489
Collapse All | Expand All

(-)a/branches/ucs-3.2/ucs-3.2-1/management/univention-directory-replication/replication.py (-210 / +5 lines)
 Lines 68-126   if listener.baseConfig['ldap/server/type'] == 'slave': Link Here 
68
if listener.baseConfig['ldap/slave/filter']:
68
if listener.baseConfig['ldap/slave/filter']:
69
	filter=listener.baseConfig['ldap/slave/filter']
69
	filter=listener.baseConfig['ldap/slave/filter']
70
70
71
#
72
# init flatmode if enabled
73
#
74
flatmode = False
75
flatmode_ldap={ 'lo': None }
76
flatmode_mapping = []
77
flatmode_container = {}
78
flatmode_module_prefix = 'ldap/replication/flatmode/module/'
79
flatmode_container_prefix = 'ldap/replication/flatmode/container/'
80
81
univention.debug.debug(
82
	univention.debug.LISTENER,
83
	univention.debug.INFO,
84
	'replication flatmode enabled by UCR: %s' % listener.baseConfig.get('ldap/replication/flatmode','no'))
85
86
if listener.baseConfig.is_true('ldap/replication/flatmode', False):
87
	# flatmode is enabled
88
	try:
89
		import univention.admin.uldap
90
		import univention.admin.objects
91
		import univention.admin.modules
92
	except Exception, ex:
93
		univention.debug.debug(univention.debug.LISTENER, univention.debug.ERROR, 'cannot import univention directory manager modules: %s' % str(ex))
94
	else:
95
		# all modules imported
96
		for	key_mod in listener.baseConfig.keys():
97
			# iterate over all UCR variables
98
			if key_mod.startswith( flatmode_module_prefix ):
99
				# found module entry
100
				id=key_mod[ len( flatmode_module_prefix ) : ]
101
				val_mod = listener.baseConfig[ key_mod ]
102
				# find container entry
103
				key_cn = '%s%s' % (flatmode_container_prefix, id)
104
				if listener.baseConfig.get(key_cn):
105
					val_cn = listener.baseConfig[ key_cn ]
106
					# get module
107
					mod = univention.admin.modules.get( val_mod )
108
					if not mod:
109
						univention.debug.debug(univention.debug.LISTENER, univention.debug.ERROR, 'replication flatmode: could not get module %s' % val_mod)
110
					else:
111
						entry = { 'module': mod, 'type': val_mod, 'container': val_cn }
112
						univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication flatmode: saving objects of type %s in %s' % (val_mod, val_cn))
113
						flatmode_mapping.append( entry )
114
						flatmode_container[ val_cn ] = False
115
						flatmode = True
116
				else:
117
					univention.debug.debug(univention.debug.LISTENER, univention.debug.ERROR, 'replication flatmode: cannot find UCR variable %s' % key_cn)
118
119
univention.debug.debug(
120
	univention.debug.LISTENER,
121
	univention.debug.INFO,
122
	'replication flatmode activated: %s' % flatmode)
123
124
STATE_DIR = '/var/lib/univention-directory-replication'
71
STATE_DIR = '/var/lib/univention-directory-replication'
125
LDIF_FILE = os.path.join(STATE_DIR, 'failed.ldif')
72
LDIF_FILE = os.path.join(STATE_DIR, 'failed.ldif')
126
73
 Lines 561-567   def connect(ldif=0): Link Here 
561
508
562
		local_ip='127.0.0.1'
509
		local_ip='127.0.0.1'
563
		local_port=listener.baseConfig.get('slapd/port', '7389').split(',')[0]
510
		local_port=listener.baseConfig.get('slapd/port', '7389').split(',')[0]
564
		
511
565
		try:
512
		try:
566
			connection=ldap.open(local_ip, int(local_port))
513
			connection=ldap.open(local_ip, int(local_port))
567
			connection.simple_bind_s('cn=update,'+listener.baseConfig['ldap/base'], pw)
514
			connection.simple_bind_s('cn=update,'+listener.baseConfig['ldap/base'], pw)
 Lines 625-632   def update_schema(attr): Link Here 
625
	finally:
572
	finally:
626
		listener.unsetuid()
573
		listener.unsetuid()
627
574
628
	queue = []
629
630
	print >>fp, '# This schema was automatically replicated from the master server'
575
	print >>fp, '# This schema was automatically replicated from the master server'
631
	print >>fp, '# Please do not edit this file\n'
576
	print >>fp, '# Please do not edit this file\n'
632
	subschema = ldap.schema.SubSchema(attr)
577
	subschema = ldap.schema.SubSchema(attr)
 Lines 674-810   def getOldValues( ldapconn, dn ): Link Here 
674
619
675
	return old
620
	return old
676
621
677
# check if target container exists; this function creates required containers if they are missing
678
def flatmodeCreateContainer( ldapconn, dn ):
679
	if dn in flatmode_container:
680
		if flatmode_container[dn]:
681
			return
682
683
	univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication flatmode: testing required container: %s' % dn)
684
	old = getOldValues( ldapconn, dn )
685
686
	if not old:
687
		univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication flatmode: required container does not exist: %s' % dn)
688
		tmpdn=''
689
		dnparts = univention.admin.uldap.explodeDn(dn, 0)
690
		dnparts.reverse()
691
		for dnpart in dnparts:
692
			if tmpdn:
693
				tmpdn = '%s,%s' % (dnpart, tmpdn)
694
			else:
695
				tmpdn = dnpart
696
697
			tmpold = {}
698
			tmpnew = {}
699
			objtype, objname = dnpart.split('=',1)
700
			if objtype == 'cn' or objtype == 'ou':
701
				# check if object exists in local ldap tree
702
				tmpold = getOldValues( ldapconn, tmpdn )
703
704
			if objtype == 'cn' and not tmpold:
705
				tmpnew = { 'cn': [ objname ], 'objectClass': [ 'top', 'organizationalRole' ] }
706
			elif objtype == 'ou' and not tmpold:
707
				tmpnew = { 'ou': [ objname ], 'objectClass': [ 'top', 'organizationalUnit' ] }
708
709
			if tmpnew:
710
				univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication flatmode: creating required container: %s' % tmpdn)
711
				univention.debug.debug(univention.debug.LISTENER, univention.debug.INFO, 'replication flatmode: calling handle( %s, tmpnew, tmpold ):\ntmpnew=%s' % (tmpdn, tmpnew))
712
				handler( tmpdn, tmpnew, tmpold )
713
	flatmode_container[dn] = True
714
715
716
# This function converts object dn and object attributes for flatmode.
717
# Special convertions for aach module type have to be added here.
718
# "new" is modified "by reference"
719
# the new value for "dn" is returned ("call by value")
720
def flatmodeConvertObject( entry, dn, new ):
721
	global flatmode_mapping
722
723
	# map DN
724
	rdn = univention.admin.uldap.explodeDn(dn, 0)[0]
725
	dn = '%s,%s' % (rdn, entry['container'])
726
727
	# correct entryDN
728
	if new:
729
		new['entryDN'][0] = dn
730
731
	if new.get('uniqueMember'):
732
		if flatmode_ldap['lo'] is None:
733
			univention.debug.debug(univention.debug.LISTENER, univention.debug.ERROR, 'replication flatmode: second ldap connection is not established - local replica may be corrupt!')
734
		else:
735
			newMemberDNs = []
736
			# convert all existing uniqueMember DNs
737
			for memberdn in new['uniqueMember']:
738
				try:
739
					obj = flatmode_ldap['lo'].get(memberdn,[])
740
				except Exception, ex:
741
					univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication flatmode: could not get member %s' % memberdn)
742
					obj = None
743
744
				newmember = memberdn
745
				if obj:
746
					for entry in flatmode_mapping:
747
						# test if memberdn should also be remapped
748
						if entry['module'].identify( memberdn, obj ) or entry['module'].identify( memberdn, obj ):
749
750
							rdn = univention.admin.uldap.explodeDn(memberdn, 0)[0]
751
							newmember = '%s,%s' % (rdn, entry['container'])
752
							break
753
754
				newMemberDNs.append( newmember )
755
			# set new DNs
756
			new['uniqueMember'] = newMemberDNs
757
758
	return dn
759
760
# if flatmode is enabled handlerFlatmode checks for every object if mapping is required
761
# if examined object matches to mapping "dn" and "new" are converted by flatmodeConvertObject
762
def handlerFlatmode( ldapconn, dn, new, old ):
763
	global flatmode
764
	global flatmode_mapping
765
	global flatmode_container
766
767
	if not flatmode:
768
		return dn
769
	newdn = dn
770
771
	if dn in flatmode_container:
772
		flatmode_container[dn] = True
773
774
	for entry in flatmode_mapping:
775
		if entry['module'].identify( dn, new ) or entry['module'].identify( dn, old ):
776
777
			newdn = flatmodeConvertObject( entry, dn, new )
778
779
			# test if required container is present
780
			if not flatmode_container[ entry['container'] ]:
781
				flatmodeCreateContainer( ldapconn, entry['container'] )
782
783
			univention.debug.debug(univention.debug.LISTENER, univention.debug.INFO, 'replication flatmode: mapped %s to %s' % (dn, newdn))
784
			return newdn
785
786
	return newdn
787
788
789
def flatmode_reconnect():
790
	univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication flatmode: ldap reconnect triggered')
791
	if ( flatmode_ldap.get('ldapserver') and \
792
		 flatmode_ldap.get('basedn') and \
793
		 flatmode_ldap.get('binddn') and \
794
		 flatmode_ldap.get('bindpw')):
795
		try:
796
			flatmode_ldap['lo'] = univention.uldap.access( host = flatmode_ldap['ldapserver'],
797
														   base = flatmode_ldap['basedn'],
798
														   binddn = flatmode_ldap['binddn'],
799
														   bindpw = flatmode_ldap['bindpw'],
800
														   start_tls = 2 )
801
		except Exception, ex:
802
			univention.debug.debug(univention.debug.LISTENER, univention.debug.ERROR, 'replication flatmode: ldap reconnect failed: %s' % str(ex))
803
			flatmode_ldap['lo'] = None
804
		else:
805
			if flatmode_ldap['lo'] is None:
806
				univention.debug.debug(univention.debug.LISTENER, univention.debug.ERROR, 'replication flatmode: ldap reconnect failed')
807
808
def _delete_dn_recursive(l, dn):
622
def _delete_dn_recursive(l, dn):
809
	try:
623
	try:
810
		l.delete_s(dn)
624
		l.delete_s(dn)
 Lines 824-842   def _backup_dn_recursive(l, dn): Link Here 
824
	if not os.path.exists(backup_directory):
638
	if not os.path.exists(backup_directory):
825
		os.makedirs(backup_directory)
639
		os.makedirs(backup_directory)
826
		os.chmod(backup_directory, 0700)
640
		os.chmod(backup_directory, 0700)
827
	
641
828
	backup_file = os.path.join(backup_directory, str(time.time()))
642
	backup_file = os.path.join(backup_directory, str(time.time()))
829
	fd = open(backup_file, 'w+')
643
	fd = open(backup_file, 'w+')
830
	fd.close()
644
	fd.close()
831
	os.chmod(backup_file, 0600)
645
	os.chmod(backup_file, 0600)
832
	univention.debug.debug(univention.debug.LISTENER, univention.debug.PROCESS, 'replication: dump %s to %s' % (dn, backup_file))
646
	univention.debug.debug(univention.debug.LISTENER, univention.debug.PROCESS, 'replication: dump %s to %s' % (dn, backup_file))
833
	
647
834
	fd = open(backup_file, 'w+')
648
	fd = open(backup_file, 'w+')
835
	ldif_writer = ldifparser.LDIFWriter(fd)
649
	ldif_writer = ldifparser.LDIFWriter(fd)
836
	for dn,entry in l.search_s(dn, ldap.SCOPE_SUBTREE, '(objectClass=*)', attrlist=['*', '+']):
650
	for dn,entry in l.search_s(dn, ldap.SCOPE_SUBTREE, '(objectClass=*)', attrlist=['*', '+']):
837
		ldif_writer.unparse(dn,entry)
651
		ldif_writer.unparse(dn,entry)
838
	fd.close()
652
	fd.close()
839
		
653
840
def _get_current_modrdn_link():
654
def _get_current_modrdn_link():
841
	return os.path.join(STATE_DIR, 'current_modrdn')
655
	return os.path.join(STATE_DIR, 'current_modrdn')
842
656
 Lines 874-880   def _read_dn_from_file(filename): Link Here 
874
def handler(dn, new, listener_old, operation):
688
def handler(dn, new, listener_old, operation):
875
	global reconnect
689
	global reconnect
876
	global slave
690
	global slave
877
	global flatmode
878
	if not slave:
691
	if not slave:
879
		return 1
692
		return 1
880
693
 Lines 908-916   def handler(dn, new, listener_old, operation): Link Here 
908
		else:
721
		else:
909
			connected=1
722
			connected=1
910
723
911
	if flatmode:
912
		dn = handlerFlatmode( l, dn, new, listener_old )
913
914
	try:
724
	try:
915
725
916
		if listener.baseConfig.get('ldap/replication/filesystem/check', 'false').lower() in ['true', 'yes']:
726
		if listener.baseConfig.get('ldap/replication/filesystem/check', 'false').lower() in ['true', 'yes']:
 Lines 1035-1041   def handler(dn, new, listener_old, operation): Link Here 
1035
						_delete_dn_recursive(l, old_dn)
845
						_delete_dn_recursive(l, old_dn)
1036
					else:
846
					else:
1037
						univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication: no old dn has been found')
847
						univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication: no old dn has been found')
1038
					
848
1039
					if not old:
849
					if not old:
1040
						_add_object_from_new(l, dn, new)
850
						_add_object_from_new(l, dn, new)
1041
					elif old:
851
					elif old:
 Lines 1214-1234   def init_slapd(arg): Link Here 
1214
	listener.run('/etc/init.d/slapd', ['slapd', arg], uid=0)
1024
	listener.run('/etc/init.d/slapd', ['slapd', arg], uid=0)
1215
	time.sleep(1)
1025
	time.sleep(1)
1216
1026
1217
def setdata(key, value):
1218
	if key == 'bindpw':
1219
		univention.debug.debug(univention.debug.LISTENER, univention.debug.INFO, 'replication: listener passed key="%s" value="<HIDDEN>"' % key)
1220
	else:
1221
		univention.debug.debug(univention.debug.LISTENER, univention.debug.INFO, 'replication: listener passed key="%s" value="%s"' % (key, value))
1222
1223
	if key in [ 'ldapserver', 'basedn', 'binddn', 'bindpw' ]:
1224
		flatmode_ldap[ key ] = value
1225
	else:
1226
		univention.debug.debug(univention.debug.LISTENER, univention.debug.INFO, 'replication: listener passed unknown data (key="%s" value="%s")' % (key, value))
1227
1228
	if key == 'ldapserver':
1229
		univention.debug.debug(univention.debug.LISTENER, univention.debug.WARN, 'replication: ldap server changed to %s' % value)
1230
		if flatmode:
1231
			flatmode_reconnect()
1232
1027
1233
if __name__ == '__main__':
1028
if __name__ == '__main__':
1234
	handler('foo', {'foo': 'bar'}, {'foo': 'baz'})
1029
	handler('foo', {'foo': 'bar'}, {'foo': 'baz'})

Return to bug 30489