From 93de3c35414cc61788a1565a2a95ab13ad23e857 Mon Sep 17 00:00:00 2001 From: Thomas Mieslinger Date: Tue, 13 Oct 2026 12:28:14 +0200 Subject: [PATCH] fix(dim): scope "create rr from pool" to the pool's layer3domain rr_create_from_pool() called _ip_mark() without a layer3domain, so the "already in use" check looked at all layer3domains. When the first free address of the pool was Static in another layer3domain, the command failed with " from layer3domain is already allocated" - and kept failing, because the allocator hands out the same first free address every time. ipblock_get_ip() ("modify pool P get ip") already passes pool.layer3domain; do the same here. ITOUDP-8009 Co-Authored-By: Claude Opus 5.5 --- .../t/layer3domain-rr-create-from-pool.t | 87 +++++++++++++++++++ dim/CHANGES | 1 + dim/dim/rpc.py | 2 +- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 dim-testsuite/t/layer3domain-rr-create-from-pool.t diff --git a/dim-testsuite/t/layer3domain-rr-create-from-pool.t b/dim-testsuite/t/layer3domain-rr-create-from-pool.t new file mode 100644 index 0000000..229d7e4 --- /dev/null +++ b/dim-testsuite/t/layer3domain-rr-create-from-pool.t @@ -0,0 +1,87 @@ +# ITOUDP-8009: "create rr ... from POOL" must only look at the layer3domain of +# POOL when it checks whether the allocated address is already in use. The same +# address being Static in another layer3domain is not a conflict. +$ ndcli create layer3domain two type vrf rd 15143:1 + +$ ndcli create container 10.0.0.0/8 layer3domain default +INFO - Creating container 10.0.0.0/8 in layer3domain default +$ ndcli create container 10.0.0.0/8 layer3domain two +INFO - Creating container 10.0.0.0/8 in layer3domain two + +$ ndcli create pool p layer3domain default +$ ndcli create pool p2 layer3domain two + +$ ndcli modify pool p add subnet 10.0.0.0/24 +INFO - Created subnet 10.0.0.0/24 in layer3domain default +WARNING - Creating zone 0.0.10.in-addr.arpa without profile +WARNING - Primary NS for this Domain is now localhost. +$ ndcli modify pool p2 add subnet 10.0.0.0/24 --allow-overlap +INFO - Created subnet 10.0.0.0/24 in layer3domain two +WARNING - 10.0.0.0/24 in layer3domain two overlaps with 10.0.0.0/24 in layer3domain default +INFO - Creating view two in zone 0.0.10.in-addr.arpa without profile + +$ ndcli create zone a.de +WARNING - Creating zone a.de without profile +WARNING - Primary NS for this Domain is now localhost. + +# 10.0.0.1 is now Static in layer3domain two ... +$ ndcli create rr other.a.de. from p2 +INFO - Marked IP 10.0.0.1 from layer3domain two as static +INFO - Creating RR other A 10.0.0.1 in zone a.de +INFO - Creating RR 1 PTR other.a.de. in zone 0.0.10.in-addr.arpa view two +created:2026-10-13 12:00:00 +ip:10.0.0.1 +layer3domain:two +mask:255.255.255.0 +modified:2026-10-13 12:00:00 +modified_by:admin +pool:p2 +ptr_target:other.a.de. +reverse_zone:0.0.10.in-addr.arpa +status:Static +subnet:10.0.0.0/24 + +# ... and still the first free address of pool p in layer3domain default +$ ndcli create rr a.de. from p +INFO - Marked IP 10.0.0.1 from layer3domain default as static +INFO - Creating RR @ A 10.0.0.1 in zone a.de +INFO - Creating RR 1 PTR a.de. in zone 0.0.10.in-addr.arpa view default +created:2026-10-13 12:00:00 +ip:10.0.0.1 +layer3domain:default +mask:255.255.255.0 +modified:2026-10-13 12:00:00 +modified_by:admin +pool:p +ptr_target:a.de. +reverse_zone:0.0.10.in-addr.arpa +status:Static +subnet:10.0.0.0/24 + +# "get ip" from a pool already behaved like this +$ ndcli modify pool p2 get ip +created:2026-10-13 12:00:00 +ip:10.0.0.2 +layer3domain:two +mask:255.255.255.0 +modified:2026-10-13 12:00:00 +modified_by:admin +pool:p2 +reverse_zone:0.0.10.in-addr.arpa +status:Static +subnet:10.0.0.0/24 +$ ndcli create rr b.a.de. from p +INFO - Marked IP 10.0.0.2 from layer3domain default as static +INFO - Creating RR b A 10.0.0.2 in zone a.de +INFO - Creating RR 2 PTR b.a.de. in zone 0.0.10.in-addr.arpa view default +created:2026-10-13 12:00:00 +ip:10.0.0.2 +layer3domain:default +mask:255.255.255.0 +modified:2026-10-13 12:00:00 +modified_by:admin +pool:p +ptr_target:b.a.de. +reverse_zone:0.0.10.in-addr.arpa +status:Static +subnet:10.0.0.0/24 diff --git a/dim/CHANGES b/dim/CHANGES index 0bb36d3..91b5551 100644 --- a/dim/CHANGES +++ b/dim/CHANGES @@ -1,5 +1,6 @@ to be released ------ +* fix `create rr ... from POOL` rejecting an address that is only in use in another layer3domain (ITOUDP-8009) * added ldap pseudo user sync to manage_dim (introduces is_pseudo column, LDAP_PSEUDO_USER_BASE, LDAP_BIND_DN, and LDAP_BIND_PASSWORD configurations) * added automated database schema mismatch verification check on application startup * reject attribute names containing colons during deletion to prevent silent failure from incorrect key-value input diff --git a/dim/dim/rpc.py b/dim/dim/rpc.py index 6a3f454..05243c5 100644 --- a/dim/dim/rpc.py +++ b/dim/dim/rpc.py @@ -2206,7 +2206,7 @@ def rr_create(self, zone=None, views=None, ttl=None, comment=None, profile=False @updating def rr_create_from_pool(self, name, pool, ttl=None, comment=None, full=False, attributes=None, views=None): pool = get_pool(pool) - ipblock = self._ip_mark(allocate_ip(pool), attributes=attributes, pool=pool) + ipblock = self._ip_mark(allocate_ip(pool), layer3domain=pool.layer3domain, attributes=attributes, pool=pool) if ipblock: type = 'A' if ipblock.version == 6: