View | Details | Raw Unified | Return to bug 55391 | Differences between
and this patch

Collapse All | Expand All

(-)a/management/univention-management-console-module-ipchange/umc/python/ipchange/__init__.py (-56 / +91 lines)
 Lines 59-137   class Instance(Base): Link Here 
59
		'''Return a dict with all necessary values for ipchange read from the current
59
		'''Return a dict with all necessary values for ipchange read from the current
60
		status of the system.'''
60
		status of the system.'''
61
61
62
		# ignore link local addresses (no DHCP address received)
62
		# ignore link local or loopback addresses (no DHCP address received)
63
		network = ipaddress.IPv4Network(f'{ip}/{netmask}', False)
63
		network = ipaddress.ip_network(f'{ip}/{netmask}', False)
64
		if network.is_link_local:
64
		if network.is_link_local or network.is_loopback:
65
			MODULE.error('Ignore link local address change.')
65
			MODULE.error('Ignore link local or loopback address change.')
66
			return
66
			return
67
67
68
		# set attribute aRecord(<split>.|<trim>0) or aAAARecord(<split>:|<trim>0000) for IP version 4 or 6
69
		if network.version == 4:
70
			attribute = 'aRecord'
71
			sattribute = '.'
72
			tattribute = '0'
73
		if network.version == 6:
74
			attribute = 'aAAARecord'
75
			sattribute = ':'
76
			tattribute = '0000'
77
68
		lo, position = univention.admin.uldap.getAdminConnection()
78
		lo, position = univention.admin.uldap.getAdminConnection()
69
		hmodule = univention.admin.modules.get('dns/host_record')
79
		hmodule = univention.admin.modules.get('dns/host_record')
80
		rmodule = univention.admin.modules.get('dns/reverse_zone')
81
		fmodule = univention.admin.modules.get('dns/forward_zone')
70
		cmodule = univention.admin.modules.get(f'computers/{role}')
82
		cmodule = univention.admin.modules.get(f'computers/{role}')
83
		server = cmodule.object(None, lo, position, self.user_dn)
84
		server.open()
85
86
		# get the current server status filtert by IP version and init fqdns to change the host records too
87
		saddresses = [entry for entry in server.get('ip') if ipaddress.ip_address(entry).version == network.version]
88
		fqdns = [server.get('fqdn')]
89
90
		if ip:
91
			naddress = ipaddress.ip_address(ip).exploded
92
		if oldip:
93
			oaddress = ipaddress.ip_address(oldip).exploded
94
		if oldip and oaddress != naddress:
95
			for address in [oaddress, oldip]:
96
				if address not in saddresses:
97
					saddresses.append(address)
98
99
		# check if already used by host record ( raise by first match )
100
		res = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', filter=filter_format(f'(|({attribute}=%s)({attribute}=%s))', (naddress,ip)))
101
		for name in [entry['name'] for entry in res if 'name' in entry]:
102
			raise BadRequest(f'The IP address is already in use by host record for : {name}')
103
104
		# change host records first ( we need to prepare this for a new pTRRecord )
105
		ucr.load()
106
107
		# FIXME: This should be done for UCS-in-AD domains as well!
108
		# FIXED? Works, but it is't stable!
109
		#  ( Sometimes the S4 connector resync old adresses. Do we have to wait for a replication? )
110
		if 'samba' in ucr.get('dns/backend'):
111
			for host in ['gc._msdcs','DomainDnsZones','ForestDnsZones']:
112
				fqdns.append(f'{host}.%s' % ucr.get('domainname'))
113
114
		if ucr.is_true('ucs/server/sso/autoregistraton', True):
115
			fqdns.append(ucr.get('ucs/server/sso/fqdn'))
71
116
72
		# check if already used
117
		for fqdn in fqdns:
73
		res = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', filter=filter_format('aRecord=%s', (ip,)))
118
			forwardobjects = univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=None)
74
		used_by = [entry['name'] for entry in res if 'name' in entry]
119
			for forwardobject in forwardobjects:
75
		if used_by:
120
				zone = forwardobject.get('zone')
76
			raise BadRequest(f'The IP address is already in use by host record(s) for: {", ".join(used_by)}')
121
				if not fqdn.endswith(zone):
122
					continue
123
				name = fqdn[:-(len(zone) + 1)]
124
				for address in saddresses:
125
					records = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', superordinate=forwardobject, filter=filter_format(f'(&(relativeDomainName=%s)({attribute}=%s))', (name, address)))
126
					for record in records:
127
						record.open()
128
						record['a'].remove(address)
129
						record['a'].append(naddress)
130
						record.modify()
77
131
78
		# do we have a forward zone for this IP address?
132
		# do we have a forward zone for this IP addresses?
79
		if oldip and oldip != ip:
133
		for address in saddresses:
80
			fmodule = univention.admin.modules.get('dns/forward_zone')
134
			for forwardobject in univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=filter_format(f'({attribute}=%s)', (address,))):
81
			for forwardobject in univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=filter_format('(aRecord=%s)', (oldip,))):
82
				forwardobject.open()
135
				forwardobject.open()
83
				forwardobject['a'].remove(oldip)
136
				forwardobject['a'].remove(address)
84
				forwardobject['a'].append(ip)
137
				forwardobject['a'].append(naddress)
85
				forwardobject.modify()
138
				forwardobject.modify()
86
139
87
		# remove old DNS reverse entries with old IP
88
		server = cmodule.object(None, lo, position, self.user_dn)
89
		server.open()
90
		current_ips = server['ip']
91
		for entry in server['dnsEntryZoneReverse']:
92
			if entry[1] in current_ips:
93
				server['dnsEntryZoneReverse'].remove(entry)
94
95
		# change IP
96
		server['ip'] = ip
97
		MODULE.info(f'Change IP to {ip}')
98
		server.modify()
99
100
		# do we have a new reverse zone for this IP address?
140
		# do we have a new reverse zone for this IP address?
101
		rmodule = univention.admin.modules.get('dns/reverse_zone')
141
		parts = network.network_address.exploded.split(sattribute)
102
		parts = network.network_address.exploded.split('.')
142
		while parts[-1] == tattribute:
103
		while parts[-1] == '0':
104
			parts.pop()
143
			parts.pop()
105
144
106
		while parts:
145
		while parts:
107
			subnet = '.'.join(parts)
146
			subnet = sattribute.join(parts)
108
			parts.pop()
147
			parts.pop()
109
			filter = filter_format('(subnet=%s)', (subnet,))
148
			reverseobject = univention.admin.modules.lookup(rmodule, None, lo, scope='sub', superordinate=None, filter=filter_format('(subnet=%s)', (subnet,)))
110
			reverseobject = univention.admin.modules.lookup(rmodule, None, lo, scope='sub', superordinate=None, filter=filter)
111
			if reverseobject:
149
			if reverseobject:
112
				server = cmodule.object(None, lo, position, self.user_dn)
113
				server.open()
150
				server.open()
114
				server['dnsEntryZoneReverse'].append([reverseobject[0].dn, ip])
151
				server['dnsEntryZoneReverse'].append([reverseobject[0].dn, naddress])
115
				server.modify()
152
				server.modify()
116
				break
153
				break
117
154
118
		# Change ucs-sso entry
155
		# remove old server entries with old server addresses
119
		# FIXME: this should be done for UCS-in-AD domains as well!
156
		server.open()
120
		ucr.load()
157
		for zone in ['dnsEntryZoneReverse', 'dnsEntryZoneForward']:
121
		sso_fqdn = ucr.get('ucs/server/sso/fqdn')
158
			for entry in server[zone]:
122
		if ucr.is_true('ucs/server/sso/autoregistraton', True):
159
				if entry[1] in saddresses:
123
			fmodule = univention.admin.modules.get('dns/forward_zone')
160
					server[zone].remove(entry)
124
			forwardobjects = univention.admin.modules.lookup(fmodule, None, lo, scope='sub', superordinate=None, filter=None)
161
125
			for forwardobject in forwardobjects:
162
		# change/append server address
126
				zone = forwardobject.get('zone')
163
		server['ip'].append(naddress)
127
				if not sso_fqdn.endswith(zone):
164
		MODULE.info(f'Change IP address {ip} for {fqdns[0]}')
128
					continue
165
		server.modify()
129
				sso_name = sso_fqdn[:-(len(zone) + 1)]
166
130
				for current_ip in current_ips:
167
		# cleanup any old ip addresses
131
					records = univention.admin.modules.lookup(hmodule, None, lo, scope='sub', superordinate=forwardobject, filter=filter_format('(&(relativeDomainName=%s)(aRecord=%s))', (sso_name, current_ip)))
168
		server.open()
132
					for record in records:
169
		for entry in server['ip']:
133
						record.open()
170
			if entry in saddresses:
134
						if oldip in record['a']:
171
				server['ip'].remove(entry)
135
							record['a'].remove(oldip)
172
		server.modify()
136
						record['a'].append(ip)
137
						record.modify()

Return to bug 55391