@@ -102,19 +102,22 @@ def is_unique_ip(
102
102
ip_interface : Union [IPv4Interface , IPv6Interface ],
103
103
server : "Server" ,
104
104
addr_types : list [str ],
105
- is_net : bool ,
106
105
attribute_id : Optional [int ] = None ,
107
106
) -> None :
108
- """Validate if IPv4/IPv6 interface is unique
107
+ """Validate if given IP address is unique
109
108
110
109
Raises a ValidationError if intern_ip or any other attribute of type inet
111
110
with this ip_address already exists.
112
111
113
- :param ip_interface:
114
- :param server:
115
- :param addr_types:
116
- :param is_net:
117
- :param attribute_id:
112
+ :param ip_interface: The IP address to validate
113
+ :param server: The current Server object to which the new IP address is
114
+ to be assigned
115
+ :param addr_types: Verify only against Servers of given IP_ADDR_TYPES.
116
+ Allows for conflicting IP addresses, as long as they are on
117
+ Servers with different IP_ADDR_TYPES.
118
+ :param attribute_id: Verify only against this attribute. Allows for having
119
+ conflicting IP addresses on different attributes, as long
120
+ as they are on different Server objects.
118
121
:return:
119
122
"""
120
123
@@ -127,40 +130,88 @@ def is_unique_ip(
127
130
# the same IP address as long as it is in different attributes.
128
131
129
132
duplicates = []
130
- object_id = server .server_id
131
133
132
- if is_net :
133
- servertype_inet_attr_q = Q ( server__servertype = server . servertype_id )
134
- servertype_intern_ip_q = Q (servertype = server .servertype_id )
135
- inet_attr_q = Q ( value__net_overlaps = ip_interface )
136
- intern_ip_q = Q ( intern_ip__net_overlaps = ip_interface )
134
+ # TODO: Make attribute_id mandatory when intern_ip is gone.
135
+ if attribute_id :
136
+ object_attribute_q = Q (server_id = server .server_id ) | ~ Q (
137
+ attribute_id = attribute_id
138
+ )
137
139
else :
138
- servertype_inet_attr_q = Q ()
139
- servertype_intern_ip_q = Q ()
140
- inet_attr_q = Q (value = ip_interface )
141
- intern_ip_q = Q (intern_ip = ip_interface )
140
+ object_attribute_q = Q (server_id = server .server_id )
141
+
142
+ # TODO: Remove intern_ip.
143
+ for d in Server .objects .filter (
144
+ Q (
145
+ Q (intern_ip = ip_interface ) # IP address
146
+ & Q (servertype__ip_addr_type__in = addr_types ) # IP address type
147
+ & ~ Q (server_id = server .server_id ) # Self-server
148
+ )
149
+ ):
150
+ duplicates .append (f"{ d .hostname } (intern_ip)" )
151
+
152
+ for d in ServerInetAttribute .objects .filter (
153
+ Q (
154
+ Q (value = ip_interface ) # IP address
155
+ & Q (server__servertype__ip_addr_type__in = addr_types ) # IP address type
156
+ & ~ object_attribute_q # Self-server
157
+ )
158
+ ):
159
+ duplicates .append (f"{ d .server .hostname } ({ d .attribute } )" )
160
+
161
+ if duplicates :
162
+ raise ValidationError (
163
+ f"Can't set IP address { ip_interface } on { server .hostname } , conflicts with: { ', ' .join (duplicates )} "
164
+ )
165
+
166
+
167
+ def network_overlaps (
168
+ ip_interface : Union [IPv4Interface , IPv6Interface ],
169
+ server : "Server" ,
170
+ addr_types : list [str ],
171
+ attribute_id : Optional [int ] = None ,
172
+ ) -> None :
173
+ """Validate if given IP prefix is unique
174
+
175
+ Raises a ValidationError if the IP prefix overlaps with any other existing
176
+ objects network of the given servertype.
177
+
178
+ :param ip_interface: The IP address to validate
179
+ :param server: The current Server object to which the new IP prefix is
180
+ to be assigned
181
+ :param addr_types: Verify only against Servers of given IP_ADDR_TYPES.
182
+ Allows for overlapping IP prefixes, as long as they are on
183
+ Servers with different IP_ADDR_TYPES.
184
+ :param attribute_id: Verify only against this attribute. Allows for having
185
+ overlapping IP prefixes on different attributes, as long
186
+ as they are on different Server objects.
187
+ :return:
188
+ """
189
+
190
+ duplicates = []
142
191
143
192
# TODO: Make attribute_id mandatory when intern_ip is gone.
144
193
if attribute_id :
145
- object_attribute_q = Q (server_id = object_id ) | ~ Q (attribute_id = attribute_id )
194
+ object_attribute_q = Q (server_id = server .server_id ) | ~ Q (
195
+ attribute_id = attribute_id
196
+ )
146
197
else :
147
- object_attribute_q = Q (server_id = object_id )
198
+ object_attribute_q = Q (server_id = server . server_id )
148
199
149
200
# TODO: Remove intern_ip.
150
201
for d in Server .objects .filter (
151
202
Q (
152
- servertype_intern_ip_q # Servertype
153
- & intern_ip_q # IP address
203
+ Q ( servertype = server . servertype_id ) # Servertype
204
+ & Q ( intern_ip__net_overlaps = ip_interface ) # IP address
154
205
& Q (servertype__ip_addr_type__in = addr_types ) # IP address type
155
- & ~ Q (server_id = object_id ) # Self-server
206
+ & ~ Q (server_id = server . server_id ) # Self-server
156
207
)
157
208
):
158
209
duplicates .append (f"{ d .hostname } (intern_ip)" )
159
210
160
211
for d in ServerInetAttribute .objects .filter (
161
212
Q (
162
- servertype_inet_attr_q # Servertype
163
- & inet_attr_q # IP address
213
+ Q ( server__servertype = server . servertype_id ) # Servertype
214
+ & Q ( value__net_overlaps = ip_interface ) # IP address
164
215
& Q (server__servertype__ip_addr_type__in = addr_types ) # IP address type
165
216
& ~ object_attribute_q # Self-server
166
217
)
@@ -495,10 +546,10 @@ def clean(self):
495
546
496
547
if ip_addr_type == "host" :
497
548
is_ip_address (self .intern_ip )
498
- is_unique_ip (self .intern_ip , self , ["host" ], False )
549
+ is_unique_ip (self .intern_ip , self , ["host" ])
499
550
elif ip_addr_type == "network" :
500
551
is_network (self .intern_ip )
501
- is_unique_ip (self .intern_ip , self , ["network" ], True )
552
+ network_overlaps (self .intern_ip , self , ["network" ])
502
553
elif ip_addr_type == "loadbalancer" :
503
554
is_ip_address (self .intern_ip )
504
555
@@ -726,10 +777,10 @@ def clean(self):
726
777
)
727
778
elif ip_addr_type == "host" :
728
779
is_ip_address (self .value )
729
- is_unique_ip (self .value , self .server , ["host" ], False , self .attribute_id )
780
+ is_unique_ip (self .value , self .server , ["host" ], self .attribute_id )
730
781
elif ip_addr_type == "network" :
731
782
is_network (self .value )
732
- is_unique_ip (self .value , self .server , ["network" ], True , self .attribute_id )
783
+ network_overlaps (self .value , self .server , ["network" ], self .attribute_id )
733
784
elif ip_addr_type == "loadbalancer" :
734
785
is_ip_address (self .value )
735
786
0 commit comments