@@ -101,24 +101,23 @@ def is_ip_address(ip_interface: Union[IPv4Interface, IPv6Interface]) -> None:
101101def is_unique_ip (
102102 ip_interface : Union [IPv4Interface , IPv6Interface ],
103103 server : "Server" ,
104- exclude_addr_types : list [str ],
105- attribute_id : Optional [str ] = None ,
104+ addr_types : list [str ],
105+ is_net : bool ,
106+ attribute_id : Optional [int ] = None ,
106107) -> None :
107- """Validate if IPv4/IPv6 address is unique
108+ """Validate if IPv4/IPv6 interface is unique
108109
109110 Raises a ValidationError if intern_ip or any other attribute of type inet
110111 with this ip_address already exists.
111112
112113 :param ip_interface:
113- :param object_id:
114+ :param server:
115+ :param addr_types:
116+ :param is_net:
114117 :param attribute_id:
115118 :return:
116119 """
117120
118- # We avoid querying the duplicate hosts here and giving the user
119- # detailed information because checking with exists is cheaper than
120- # querying the server and this is a validation and should be fast.
121-
122121 # Always exclude the current object_id from the query because we allow
123122 # duplication of data between the legacy (intern_ip, primary_ip6) and
124123 # the modern (ipv4, ipv6) attributes.
@@ -130,7 +129,18 @@ def is_unique_ip(
130129 duplicates = []
131130 object_id = server .server_id
132131
133- # TODO: Make "aid" mandatory when intern_ip is gone.
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 )
137+ else :
138+ servertype_inet_attr_q = Q (True )
139+ servertype_intern_ip_q = Q (True )
140+ inet_attr_q = Q (value = ip_interface )
141+ intern_ip_q = Q (intern_ip = ip_interface )
142+
143+ # TODO: Make attribute_id mandatory when intern_ip is gone.
134144 if attribute_id :
135145 object_attribute_condition = Q (server_id = object_id ) | ~ Q (
136146 attribute_id = attribute_id
@@ -139,14 +149,23 @@ def is_unique_ip(
139149 object_attribute_condition = Q (server_id = object_id )
140150
141151 # TODO: Remove intern_ip.
142- for d in Server .objects .filter (intern_ip = ip_interface ).exclude (
143- Q (servertype__ip_addr_type__in = exclude_addr_types ) | Q (server_id = object_id )
152+ for d in Server .objects .filter (
153+ Q (
154+ servertype_intern_ip_q
155+ & intern_ip_q
156+ & Q (servertype__ip_addr_type__in = addr_types )
157+ & ~ Q (server_id = object_id )
158+ )
144159 ):
145160 duplicates .append (f"{ d .hostname } (intern_ip)" )
146161
147- for d in ServerInetAttribute .objects .filter (value = ip_interface ).exclude (
148- Q (server__servertype__ip_addr_type__in = exclude_addr_types )
149- | object_attribute_condition
162+ for d in ServerInetAttribute .objects .filter (
163+ Q (
164+ servertype_inet_attr_q
165+ & inet_attr_q
166+ & Q (server__servertype__ip_addr_type__in = addr_types )
167+ )
168+ & ~ object_attribute_condition
150169 ):
151170 duplicates .append (f"{ d .server .hostname } ({ d .attribute } )" )
152171
@@ -187,43 +206,6 @@ def inet_to_python(obj: object) -> Union[IPv4Interface, IPv6Interface]:
187206 raise ValidationError (str (error ))
188207
189208
190- def network_overlaps (
191- ip_interface : Union [IPv4Interface , IPv6Interface ],
192- servertype_id : str ,
193- object_id : int ,
194- ) -> None :
195- """Validate if network overlaps with other objects of the servertype_id
196-
197- Raises a ValidationError if the ip network overlaps with any other existing
198- objects network of the given servertype.
199-
200- :param ip_interface:
201- :param servertype_id:
202- :param object_id:
203- :return:
204- """
205-
206- overlaps = (
207- Server .objects .filter (
208- servertype = servertype_id , intern_ip__net_overlaps = ip_interface
209- )
210- .exclude (server_id = object_id )
211- .exists ()
212- or
213- # TODO: We should filter for attribute id here as well to have
214- # consistent bebaviour with ip_addr_type: host and is_unique.
215- ServerInetAttribute .objects .filter (
216- server__servertype = servertype_id , value__net_overlaps = ip_interface
217- )
218- .exclude (server_id = object_id )
219- .exists ()
220- )
221- if overlaps :
222- raise ValidationError (
223- "{0} overlaps with network of another object" .format (str (ip_interface ))
224- )
225-
226-
227209class Servertype (models .Model ):
228210 servertype_id = models .CharField (
229211 max_length = 32 ,
@@ -515,14 +497,12 @@ def clean(self):
515497
516498 if ip_addr_type == "host" :
517499 is_ip_address (self .intern_ip )
518- is_unique_ip (self .intern_ip , self , ["network" , "loadbalancer" ])
519- elif ip_addr_type == "loadbalancer" :
520- is_ip_address (self .intern_ip )
500+ is_unique_ip (self .intern_ip , self , ["host" ], False )
521501 elif ip_addr_type == "network" :
522502 is_network (self .intern_ip )
523- network_overlaps (
524- self . intern_ip , self . servertype . servertype_id , self . server_id
525- )
503+ is_unique_ip ( self . intern_ip , self , [ "network" ], True )
504+ elif ip_addr_type == "loadbalancer" :
505+ is_ip_address ( self . intern_ip )
526506
527507 def get_attributes (self , attribute ):
528508 model = ServerAttribute .get_model (attribute .type )
@@ -748,16 +728,12 @@ def clean(self):
748728 )
749729 elif ip_addr_type == "host" :
750730 is_ip_address (self .value )
751- is_unique_ip (
752- self .value , self .server , ["network" , "loadbalancer" ], self .attribute_id
753- )
754- elif ip_addr_type == "loadbalancer" :
755- is_ip_address (self .value )
731+ is_unique_ip (self .value , self .server , ["host" ], False , self .attribute_id )
756732 elif ip_addr_type == "network" :
757733 is_network (self .value )
758- network_overlaps (
759- self . value , self . server . servertype_id , self . server . server_id
760- )
734+ is_unique_ip ( self . value , self . server , [ "network" ], True , self . attribute_id )
735+ elif ip_addr_type == "loadbalancer" :
736+ is_ip_address ( self . value )
761737
762738
763739class ServerMACAddressAttribute (ServerAttribute ):
0 commit comments