Skip to content

Commit

Permalink
Recruit existing DNS record when adding coupled IP address
Browse files Browse the repository at this point in the history
When an IP address is created, and the DNS coupling is requested, if
the given name and zone match an existing and unmanaged DNS record,
the record is linked to the IP address and becomes managed.

0) DNS Record "R" pre-exists and has the following characteristics:
   id=1, name=foo, zone=example.com, type=A, value=10.0.0.1, managed=False

1) IP address, with address=10.0.0.1/24, cf_name=foo, cf_zone=example.com
   is requested for creation.

2) The IP address is created and points to the DNS record "R":
   address=10.0.0.1/24, cf_dns_record=1 ...

3) The DNS Record R becomes managed:
   id=1, ... , managed=True
  • Loading branch information
jean1 committed Oct 5, 2023
1 parent 4a36310 commit 6119a7b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
33 changes: 22 additions & 11 deletions netbox_dns/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,32 @@ def post_save(self, sender, **kwargs):
ip.dns_name = f"{name}.{zone.name}"
ip.save(update_fields=["dns_name"])

# create DNS record
else:
record = Record(
name=name,
zone=zone,
type=RecordTypeChoices.AAAA
if ip.family == 6
else RecordTypeChoices.A,
value=str(ip.address.ip),
managed=True,
)
# Fetch an existing (unmanaged) DNS record or create a new one
type = (RecordTypeChoices.AAAA if ip.family == 6 else RecordTypeChoices.A)
value = str(ip.address.ip)
try:
record = Record.objects.get(
name=name,
zone=zone,
value=value,
type=type,
managed=False
)
record.managed = True
except:
record = Record(
name=name,
zone=zone,
type=type,
value=value,
managed=True,
)

check_record_permission(
user, record, "netbox_dns.add_record", commit=True
)
# link record to IP Address
# Link record to IP Address
ip.custom_field_data["dns_record"] = record.id
# cosmetic: update dns_name field with FQDN
ip.dns_name = f"{name}.{zone.name}"
Expand Down Expand Up @@ -145,6 +155,7 @@ def check_record_permission(user, record, perm, commit=False):
with transaction.atomic():
# Save record when adding
# Rollback is done at the end of the transaction, unless committed

if action == "add":
record.save()

Expand Down
31 changes: 31 additions & 0 deletions netbox_dns/tests/coupling/test_ip_dns_coupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,37 @@ def test_create_ip(self):
ipaddress = IPAddress.objects.get(id=response.data["id"])
self.assertEqual(ipaddress.dns_name, f"{name}.{zone.name}")

@override_settings(PLUGINS_CONFIG={"netbox_dns": {"feature_ipam_coupling": True}})
def test_create_ip_existing_dns_record(self):
zone = self.zone
name = "test-create-ip-existing-dns-record"
addr = "10.0.0.25/24"

# Create DNS record
A = RecordTypeChoices.A
v = str(IPNetwork(addr).ip)
record = Record.objects.create(name=name, zone=zone, type=A, value=v)

# Grant permissions to user
self.add_permissions("ipam.add_ipaddress")
self.add_permissions("netbox_dns.add_record")

url = reverse("ipam-api:ipaddress-list")
data = {"address": addr, "custom_fields": {"zone": zone.id, "name": name}}
response = self.client.post(url, data, format="json", **self.header)

self.assertTrue(status.is_success(response.status_code))

# Check if "record" has been linked to and is now managed
record_id = response.data["custom_fields"]["dns_record"]["id"]
self.assertEqual(record_id, record.id)
record = Record.objects.get(id=record.id)
self.assertTrue(record.managed)
# Check value of dns_name
ipaddress = IPAddress.objects.get(id=response.data["id"])
self.assertEqual(ipaddress.dns_name, f"{name}.{zone.name}")


@override_settings(PLUGINS_CONFIG={"netbox_dns": {"feature_ipam_coupling": True}})
def test_create_ip_missing_dns_permission(self):
zone = self.zone
Expand Down

0 comments on commit 6119a7b

Please sign in to comment.