Skip to content

Commit

Permalink
Renamed the custom fields for IPAM-DNS coupling
Browse files Browse the repository at this point in the history
* The original names 'name' and 'zone' are very generic. Given that the CF names
  are global within NetBox, they were renamed so they don't clash with other field
  names so easily
  • Loading branch information
peteeckel committed Oct 16, 2023
1 parent bdb572a commit 2c6de80
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 29 deletions.
9 changes: 6 additions & 3 deletions netbox_dns/management/commands/setup_coupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def handle(self, *model_names, **options):
ipaddress_object_type = ContentType.objects.get_for_model(IPAddress)
zone_object_type = ContentType.objects.get_for_model(Zone)
record_object_type = ContentType.objects.get_for_model(Record)
customfields = ("name", "zone")
customfields = ("ipaddress_dns_record_name", "ipaddress_dns_zone_id")

if options["remove"]:
for cf in customfields:
Expand All @@ -31,6 +31,7 @@ def handle(self, *model_names, **options):
self.stderr.write(f"Custom field '{cf}' does not exist!")
else:
self.stdout.write(f"Custom field '{cf}' removed")

else:
msg = ""
for cf in customfields:
Expand All @@ -55,14 +56,16 @@ def handle(self, *model_names, **options):
)

cf_name = CustomField.objects.create(
name="name",
name="ipaddress_dns_record_name",
label="Name",
type=CustomFieldTypeChoices.TYPE_TEXT,
required=False,
group_name="DNS",
)
cf_name.content_types.set([ipaddress_object_type])
cf_zone = CustomField.objects.create(
name="zone",
name="ipaddress_dns_zone_id",
label="Zone",
type=CustomFieldTypeChoices.TYPE_OBJECT,
object_type=zone_object_type,
required=False,
Expand Down
12 changes: 6 additions & 6 deletions netbox_dns/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def pre_save(self, sender, **kwargs):
return

ip = kwargs.get("instance")
name = ip.custom_field_data.get("name")
zone_id = ip.custom_field_data.get("zone")
name = ip.custom_field_data.get("ipaddress_dns_record_name")
zone_id = ip.custom_field_data.get("ipaddress_dns_zone_id")

# Handle new IP Address only; name and zone must both be defined
if ip.id is None and name and zone_id:
Expand All @@ -51,8 +51,8 @@ def post_save(self, sender, **kwargs):

user = self.request.user
ip = kwargs.get("instance")
name = ip.custom_field_data.get("name")
zone_id = ip.custom_field_data.get("zone")
name = ip.custom_field_data.get("ipaddress_dns_record_name")
zone_id = ip.custom_field_data.get("ipaddress_dns_zone_id")
zone = Zone.objects.get(id=zone_id) if zone_id else None

# Clear the other field if one is empty, which is inconsistent
Expand All @@ -66,8 +66,8 @@ def post_save(self, sender, **kwargs):
# If permission ok, clear all fields related to DNS
check_record_permission(user, record, "netbox_dns.delete_record")
ip.dns_name = ""
ip.custom_field_data["name"] = ""
ip.custom_field_data["zone"] = None
ip.custom_field_data["ipaddress_dns_record_name"] = ""
ip.custom_field_data["ipaddress_dns_zone_id"] = None
ip.save(update_fields=["custom_field_data", "dns_name"])
record.delete()

Expand Down
14 changes: 9 additions & 5 deletions netbox_dns/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,10 @@ def save(self, *args, **kwargs):
get_plugin_config("netbox_dns", "feature_ipam_coupling")
and name_changed
):
for ip in IP.objects.filter(custom_field_data__zone=self.pk):
ip.dns_name = f'{ip.custom_field_data["name"]}.{self.name}'
for ip in IP.objects.filter(
custom_field_data__ipaddress_dns_zone_id=self.pk
):
ip.dns_name = f'{ip.custom_field_data["ipaddress_dns_record_name"]}.{self.name}'
ip.save(update_fields=["dns_name"])

self.update_soa_record()
Expand All @@ -582,10 +584,12 @@ def delete(self, *args, **kwargs):

if get_plugin_config("netbox_dns", "feature_ipam_coupling"):
# Remove coupling from IPAddress to DNS record when zone is deleted
for ip in IP.objects.filter(custom_field_data__zone=self.pk):
for ip in IP.objects.filter(
custom_field_data__ipaddress_dns_zone_id=self.pk
):
ip.dns_name = ""
ip.custom_field_data["name"] = ""
ip.custom_field_data["zone"] = None
ip.custom_field_data["ipaddress_dns_record_name"] = ""
ip.custom_field_data["ipaddress_dns_zone_id"] = None
ip.save(update_fields=["dns_name", "custom_field_data"])

super().delete(*args, **kwargs)
Expand Down
76 changes: 61 additions & 15 deletions netbox_dns/tests/coupling/test_ip_dns_coupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ def test_create_ip(self):
self.add_permissions("netbox_dns.add_record")

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

self.assertTrue(status.is_success(response.status_code))
Expand Down Expand Up @@ -86,7 +92,13 @@ def test_create_ip_existing_dns_record(self):
self.add_permissions("netbox_dns.add_record")

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

self.assertTrue(status.is_success(response.status_code))
Expand All @@ -111,7 +123,13 @@ def test_create_ip_missing_dns_permission(self):
self.add_permissions("ipam.add_ipaddress")

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

# Should be denied
Expand All @@ -136,7 +154,10 @@ def test_delete_ip(self):
ip_address = IPAddress.objects.create(
address=addr,
dns_name=f"{name}.{zone.name}",
custom_field_data={"name": name, "zone": zone.id},
custom_field_data={
"ipaddress_dns_record_name": name,
"ipaddress_dns_zone_id": zone.id,
},
)
record = Record.objects.create(
name=name,
Expand Down Expand Up @@ -172,7 +193,10 @@ def test_modify_name_existing_ip(self):
ip_address = IPAddress.objects.create(
address=addr,
dns_name=f"{name}.{zone.name}",
custom_field_data={"name": name, "zone": zone.id},
custom_field_data={
"ipaddress_dns_record_name": name,
"ipaddress_dns_zone_id": zone.id,
},
)
# Create DNS record
A = RecordTypeChoices.A
Expand All @@ -187,7 +211,12 @@ def test_modify_name_existing_ip(self):

# Change name and zone
url = reverse("ipam-api:ipaddress-list") + str(ip_address.id) + "/"
data = {"custom_fields": {"name": newname, "zone": zone2.id}}
data = {
"custom_fields": {
"ipaddress_dns_record_name": newname,
"ipaddress_dns_zone_id": zone2.id,
}
}
response = self.client.patch(url, data, format="json", **self.header)

# Check response
Expand Down Expand Up @@ -218,7 +247,10 @@ def test_modify_name_existing_ip_missing_dns_permission(self):
ip_address = IPAddress.objects.create(
address=addr,
dns_name=f"{name}.{zone.name}",
custom_field_data={"name": name, "zone": zone.id},
custom_field_data={
"ipaddress_dns_record_name": name,
"ipaddress_dns_zone_id": zone.id,
},
)
# Create DNS record
A = RecordTypeChoices.A
Expand All @@ -233,7 +265,12 @@ def test_modify_name_existing_ip_missing_dns_permission(self):

# Change name and zone
url = reverse("ipam-api:ipaddress-list") + str(ip_address.id) + "/"
data = {"custom_fields": {"name": newname, "zone": zone2.id}}
data = {
"custom_fields": {
"ipaddress_dns_record_name": newname,
"ipaddress_dns_zone_id": zone2.id,
}
}
response = self.client.patch(url, data, format="json", **self.header)

# Check response
Expand Down Expand Up @@ -262,7 +299,10 @@ def test_clear_name_existing_ip(self):
ip_address = IPAddress.objects.create(
address=addr,
dns_name=f"{name}.{zone.name}",
custom_field_data={"name": name, "zone": zone.id},
custom_field_data={
"ipaddress_dns_record_name": name,
"ipaddress_dns_zone_id": zone.id,
},
)
# Create DNS record
A = RecordTypeChoices.A
Expand All @@ -276,7 +316,7 @@ def test_clear_name_existing_ip(self):
)

url = reverse("ipam-api:ipaddress-list") + str(ip_address.id) + "/"
data = {"custom_fields": {"zone": None}}
data = {"custom_fields": {"ipaddress_dns_zone_id": None}}
response = self.client.patch(url, data, format="json", **self.header)

# Check response
Expand All @@ -287,7 +327,7 @@ def test_clear_name_existing_ip(self):
ip_address = IPAddress.objects.get(id=ip_address.id)
# Check if dns_name is empty
self.assertEqual(ip_address.dns_name, "")
cf_name = ip_address.custom_field_data.get("name")
cf_name = ip_address.custom_field_data.get("ipaddress_dns_record_name")
self.assertEqual(cf_name, "")

@override_settings(PLUGINS_CONFIG={"netbox_dns": {"feature_ipam_coupling": True}})
Expand All @@ -305,7 +345,10 @@ def test_rename_zone_existing_ip(self):
ip_address = IPAddress.objects.create(
address=addr,
dns_name=f"{name}.{zone.name}",
custom_field_data={"name": name, "zone": zone.id},
custom_field_data={
"ipaddress_dns_record_name": name,
"ipaddress_dns_zone_id": zone.id,
},
)
# Create DNS record
A = RecordTypeChoices.A
Expand Down Expand Up @@ -343,7 +386,10 @@ def test_delete_zone_existing_ip(self):
ip_address = IPAddress.objects.create(
address=addr,
dns_name=f"{name}.{zone.name}",
custom_field_data={"name": name, "zone": zone.id},
custom_field_data={
"ipaddress_dns_record_name": name,
"ipaddress_dns_zone_id": zone.id,
},
)
# Create DNS record
A = RecordTypeChoices.A
Expand All @@ -368,6 +414,6 @@ def test_delete_zone_existing_ip(self):
ip_address = IPAddress.objects.get(id=ip_address.id)
# Check if dns_name is empty
self.assertEqual(ip_address.dns_name, "")
# Check if custom field "name" is empty
cf_name = ip_address.custom_field_data.get("name")
# Check if custom field "ipaddress_dns_record_name" is empty
cf_name = ip_address.custom_field_data.get("ipaddress_dns_record_name")
self.assertEqual(cf_name, "")

0 comments on commit 2c6de80

Please sign in to comment.