Skip to content

Commit c297982

Browse files
committed
Unify network_overlaps and is_unique_ip
1 parent c9fb976 commit c297982

File tree

1 file changed

+41
-65
lines changed

1 file changed

+41
-65
lines changed

serveradmin/serverdb/models.py

Lines changed: 41 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -101,24 +101,23 @@ def is_ip_address(ip_interface: Union[IPv4Interface, IPv6Interface]) -> None:
101101
def 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-
227209
class 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

763739
class ServerMACAddressAttribute(ServerAttribute):

0 commit comments

Comments
 (0)