Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce experimental IPAM-DNS coupling feature #68

Merged
merged 20 commits into from
Oct 16, 2023
Merged

Conversation

jean1
Copy link
Contributor

@jean1 jean1 commented Sep 26, 2023

(see issue #67)
Three new custom fields are added on IP Address :

  • name,
  • zone,
  • dns_record.

Through a middleware and signals, all IP Address creation and modification are intercepted. Using the new custom fields, the corresponding DNS record is created, modified or deleted accordingly.
Permission on DNS records are enforced.
The IP address "dns_name" field is also updated.

Three new custom fields are added on IP Address :
- name,
- zone,
- dns_record.

Through a middleware and signals, all IP Address creation and modification
are intercepted. Using the new custom fields, the corresponding DNS record
is created, modified or deleted accordingly.
Permission on DNS records are enforced.
The IP address "dns_name" field is also updated.
@peteeckel
Copy link
Owner

Hi @jean1, good to see you're back again, and I hope you are well.

Would you mind rebasing on the main branch, fixing the black formatting issues and pushing an update? This is such an often-wanted feature that I would really love to merge if it works out well, at the very least as a part of the experimental ipam_integration feature for starters.

@peteeckel
Copy link
Owner

Sorry for the confusion, I'm just trying to figure out how to make GitHub run the checks without having to approve it every time, but it seems that that only works after the first pull request is merged.

I'll build a test release once everything is green (which it currently seems to be) and try it out as soon as I can. I just ask for a little patience as I'm currently in a pretty time-consuming phase in a project - should be finished mid-October. I'm really looking forward to see how it works and maybe adjust my GUI 'integration' (or rather, 'related records' functionality) with IPAM so both together make sense - having two different IPAM integration tools would be pretty confusing.

@peteeckel
Copy link
Owner

Hi @jean1, I started testing a bit and found some issues, some of them cosmetic and some related to data integrity. I'll start writing them down here as I go so you can look into them.

  • [cosmetic] The name of the custom field in the GUI is "Dns record", which looks ugly. You can define a label "DNS Record" when you create the CF, which would improve the look and make it consistent with NetBox DNS
  • [functional] When you create a zone in NetBox DNS, link an IP address to an address record in the zone in IPAM, and then rename the zone, the dns_name field for the record still shows the old zone name.
  • [functional] When you delete the zone in NetBox DNS, the dns_name does not change either (which is the same issue as above), and the "Name" custom field is also not cleared although there is no associated record with that name anymore.
  • [functional] If you then create a normal address record in NetBox DNS with the same IP address as its target and then try to edit the IP address in IPAM you get a strange error message:
    Screenshot 2023-09-30 at 21 52 22 Not sure where that comes from ...
  • [cosmetic] You can also add a group to custom fields. That would have the advantage of being able to keep all NetBox DNS related CFs neatly grouped together.

That's it for today ... when I find more I'll keep you updated. Again, thanks for your contribution, it already looks pretty useful to me!

@peteeckel
Copy link
Owner

As an afterthought ... we should be able to get away without the 'DNS Record' custom field altogether by extending the model for records with a ipam_ip_address foreign key field. That way we would get the relation from the IPAddress to the Record via the related_field and vice versa via the new field on the record.

That would also get rid of the read-only dynamic field that looks a bit strange on the IPAddress view without losing any functionality and the need to clean it up when something is done with the zone.

jean1 added 6 commits October 5, 2023 18:32
[cosmetic] The name of the custom field in the GUI is "Dns record", which
looks ugly. Define a label "DNS Record"
which would improve the look and make it consistent with NetBox DNS
[cosmetic] The name of the custom field in the GUI is "dns_record",
which looks ugly. Add a label "DNS Record" to improve the look and make
it consistent with NetBox DNS
[cosmetic] Put custom fields in the "DNS" group to keep all NetBox DNS
related CFs neatly grouped together.
When a DNS zone is renamed, and an (IPAM) IP address is linked to a "A"
or "AAAA" DNS record from this zone, the dns_name field is updated.

When a DNS zone is deleted, and an (IPAM) IP address is linked to a "A"
or "AAAA" DNS record from this zone, the dns_name field and custom field
"name" are emptied.
When a zone is renamed, and an (IPAM) IP address is linked to a "A" or
"AAAA" DNS record from this zone, the dns_name field is updated.

When a zone is deleted, and an (IPAM) IP address is linked to a "A" or
"AAAA" DNS record from this zone, the dns_name field and custom field
"name" are emptied.
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
@peteeckel
Copy link
Owner

Hi @jean1, I'm not so sure about 6119a7b.

Take the following scenario:

  • There is an existing A record for 10.0.0.1
  • Now you add the IP address 10.0.0.1/24 and link it to the existing A record. The record is now linked to the IP address and becomes managed. Fine so far.
  • For some reason you now delete the IP address 10.0.0.1/24. The A record that has become linked to it, gets removed.

It's at least a matter of taste if that should happen or not. On one side it might make sense to remove the address record when the IP address gets deleted, but on the other hand the address record has been there before and the process of adding and then removing an IP address should not have side effects such as the disappearance of an existing address record, which is somewhat unexpected at least.

I thought a bit about how that could be handled, and my general idea mentioned above - removing the custom field from the IPAddress object that points to the A record and enhancing the Record model with a one-to-one relation to ipam.IPAddress - would make it possible to handle things a bit differently:

  • When you create an IP address and link it to an existing address record, that record is updated with a reference to the IP address but not set managed
  • When you delete an IP address that is linked to a managed address record, that record is deleted.
  • When you delete an IP address that is linked to an unmanaged address record, the link in that record is cleared, but the record is left as-is.

We could make it an option setting to remove the record as well, but generally I would prefer creating and removing IP addresses to be complementary actions without side effects on DNS data.

There is also another scenario that would be made easier to handle with that approach: Modifying an IP address.

  • Create an IP address 10.0.0.1/24 and link it to an existing or non-existing zone/name combination. The address record either gets created or an existing address record gets linked to the IP address.
  • Then, change the address to 10.0.0.2/24
  • If the record was created by creating the IP address and thus is managed, it can be modified to have the new IP address as its value
  • If the record was an existing one, indicated by not being set to managed, it is only unlinked from the IP address and either a new address record is created or another existing one is linked to the address.

The difference between being a managed record or not IMHO should be that managed records can be created, changed or deleted as necessary by NetBox DNS, while unmanaged records are never touched.

Another edge case comes to my mind: What if there are several address records in the same zone with the same name pointing at the same address? Sounds stupid, possibly is, but it's perfectly legal according to the RFCs - there is nothing stopping you from doing it. There might even be an application for this ...

name1.zone1.example.com     IN    A   10.0.0.1
name1.zone1.example.com     IN    A   10.0.0.1
name1.zone1.example.com     IN    A   10.0.0.1
name1.zone1.example.com     IN    A   10.0.0.2
name1.zone1.example.com     IN    A   10.0.0.2
name1.zone1.example.com     IN    A   10.0.0.3

In this case, round robin resolution would return 10.0.0.1 for 50% of the queries, 10.0.0.2 for 33.3% and 10.0.0.3 for 16.6% - poor man's load balancing. I wouldn't want to interfere with that kind of mechanism by arbitrarily picking out and removing address records from it - which would invariably be the case if we implemented 6119a7b.

Having an ip_address FK in the Record model and not setting the address records to managed would also take care of that.

jean1 added 3 commits October 11, 2023 10:56
A new field was added to the Record model; it points to an IP Address in
the ipam module. The coupling logic is now easier to handle for certain
cases. The dns_record custom field in ipam.IPAddress was removed.
@peteeckel
Copy link
Owner

Hi @jean1, thanks!

Small issues first (not really a problem, but we should keep it in mind):

  • Black linting is failing again. I made it a custom just to run black before I commit anything, at the very least before I push to GH ... not a big deal, but it keeps commits from being declined by the workflow
  • An issue I ran into with the main branch some weeks ago: makemigrations picks a too recent NetBox migration as its base, which breaks compatibility with earlier versions.
(netbox) [root@dns netbox]# /opt/netbox/netbox/manage.py migrate 
Traceback (most recent call last):
  File "/opt/netbox/netbox/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/opt/netbox/lib/python3.8/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/opt/netbox/lib/python3.8/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/opt/netbox/lib/python3.8/site-packages/django/core/management/base.py", line 402, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/opt/netbox/lib/python3.8/site-packages/django/core/management/base.py", line 448, in execute
    output = self.handle(*args, **options)
  File "/opt/netbox/lib/python3.8/site-packages/django/core/management/base.py", line 96, in wrapped
    res = handle_func(*args, **kwargs)
  File "/opt/netbox/lib/python3.8/site-packages/django/core/management/commands/migrate.py", line 114, in handle
    executor = MigrationExecutor(connection, self.migration_progress_callback)
  File "/opt/netbox/lib/python3.8/site-packages/django/db/migrations/executor.py", line 18, in __init__
    self.loader = MigrationLoader(self.connection)
  File "/opt/netbox/lib/python3.8/site-packages/django/db/migrations/loader.py", line 58, in __init__
    self.build_graph()
  File "/opt/netbox/lib/python3.8/site-packages/django/db/migrations/loader.py", line 276, in build_graph
    self.graph.validate_consistency()
  File "/opt/netbox/lib/python3.8/site-packages/django/db/migrations/graph.py", line 198, in validate_consistency
    [n.raise_error() for n in self.node_map.values() if isinstance(n, DummyNode)]
  File "/opt/netbox/lib/python3.8/site-packages/django/db/migrations/graph.py", line 198, in <listcomp>
    [n.raise_error() for n in self.node_map.values() if isinstance(n, DummyNode)]
  File "/opt/netbox/lib/python3.8/site-packages/django/db/migrations/graph.py", line 60, in raise_error
    raise NodeNotFoundError(self.error_message, self.key, origin=self.origin)
django.db.migrations.exceptions.NodeNotFoundError: Migration netbox_dns.0026_record_ipam_ip_address dependencies reference nonexistent parent node ('ipam', '0067_ipaddress_index_host')

You can fix it pretty easily:

pete@macallan netbox-dns % git diff 
diff --git a/netbox_dns/migrations/0026_record_ipam_ip_address.py b/netbox_dns/migrations/0026_record_ipam_ip_address.py
index e5b3a3f..d04f43f 100644
--- a/netbox_dns/migrations/0026_record_ipam_ip_address.py
+++ b/netbox_dns/migrations/0026_record_ipam_ip_address.py
@@ -15,7 +15,7 @@ def remove_ipam_coupling_cf_dns_record(apps, schema_editor):
 
 class Migration(migrations.Migration):
     dependencies = [
-        ("ipam", "0067_ipaddress_index_host"),
+        ("ipam", "0066_iprange_mark_utilized"),
         ("netbox_dns", "0025_ipam_coupling_cf"),
     ]

(and what I learned from the earlier case I fell down the same hole is not only to test against the latest NetBox release, but also against the oldest supported one. I'll probably adjust the workflows to do that in the near future).

Now for some real testing ... stay tuned!

jean1 added 2 commits October 11, 2023 19:19
"makemigrations" generated a dependency on a too recent
version of Netbox. Fixed to keep compatibility with
older supported versions of netbox.
@peteeckel
Copy link
Owner

Hi @jean1, I've just started testing you new code.

One thing I noticed right now (by making a mistake, but that's how you notice that kind of thing): I forgot to enable your experimental feature, set up a couple of IP addresses filling in the custom fields, and then wondered why 'DNS Name' was not filled in and there were no address records ...

The problem is that the migration creates the CFs, and it does that whether or not the feature is enabled. I don't think we should do that, as it creates side effects that will irritate users who do not want the feature enabled.

I'm not sure whether we can hide or show CFs depending on the config setting (which would be a pretty elegant way to handle this), but if we can't I think we should move the code creating the CFs from the migration to a management command and document that it needs to be done in order to use the integration feature.

What do you think?

@peteeckel
Copy link
Owner

So far (haven't had the time to test thoroughly and systematically) this looks very good and I think we can merge soon - this is really a step forward!

I couldn't on first sight find the reason for your FIXME-comment in middleware.py - what do you think needs to be taken care of? I created, deleted and changed names and zones for IP addresses back and forth a couple of times, and so far the results look very reasonable to me, especially when I consider the 'experimental' status of the feature.

I'll do some more testing, but as I said I think this might be a merge candidate. Do you want to squash commits and migrations yourself or would you prefer me to do that? It doesn't make sense to keep 16 commits in history, and the two migrations are not necessay either (even more so as the later one reverts part of its predecessor).

Anyway - thanks for your contribution, this is really awesome!

A management command is provided (setup_coupling) to add or remove the
custom fields needed for coupling.
@jean1
Copy link
Contributor Author

jean1 commented Oct 13, 2023 via email

@peteeckel
Copy link
Owner

Hi @jean1, awesome, thanks!

I hope I'll find some time over the weekend to do some more testing, and if everything works out I'll merge as soon as possible so others can play with it as well.

There's also been some discussion in #22 that (re-) raised an approach to link IPAM to NetBox DNS more closely, and I think it could be worth a try - the connection wouldn't be using VRFs (which, as was discussed a couple of times, doesn't really work out too well) but prefixes. I think that's a new idea that could actually work. The downside is that it uses dns_name as an input field, which, as we also discussed at some point, is not ideal.

So I'll suggest improving the validation of names in dns_name to the core team, and as soon as they are more reliable we can play with that idea as well.

@peteeckel
Copy link
Owner

peteeckel commented Oct 15, 2023

Hi @jean1, have you noticed that your tests don't actually run?

__init__.py is missing in netbox_dns.tests.coupling, so pytest doesn't execute them at all ... if it does, a part of them fails:

/opt/netbox/netbox/manage.py test -v2 netbox_dns.tests.coupling
[...]
test_clear_name_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... FAIL
test_create_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... FAIL
test_create_ip_existing_dns_record (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... FAIL
test_create_ip_missing_dns_permission (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... FAIL
test_delete_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... ok
test_delete_zone_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... ok
test_modify_name_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... FAIL
test_modify_name_existing_ip_missing_dns_permission (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... ERROR
test_rename_zone_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest) ... ERROR

======================================================================
ERROR: test_modify_name_existing_ip_missing_dns_permission (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 212, in test_modify_name_existing_ip_missing_dns_permission
    ip_address = IPAddress.objects.create(
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/query.py", line 658, in create
    obj.save(force_insert=True, using=self.db)
  File "/opt/netbox/netbox/ipam/models/ip.py", line 884, in save
    super().save(*args, **kwargs)
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/base.py", line 814, in save
    self.save_base(
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/base.py", line 861, in save_base
    pre_save.send(
  File "/opt/netbox/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 176, in send
    return [
  File "/opt/netbox/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 177, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/vagrant/netbox-dns/netbox_dns/middleware.py", line 42, in pre_save
    check_record_permission(user, record, "netbox_dns.add_record")
  File "/vagrant/netbox-dns/netbox_dns/middleware.py", line 131, in check_record_permission
    raise PermissionDenied()
django.core.exceptions.PermissionDenied

======================================================================
ERROR: test_rename_zone_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 299, in test_rename_zone_existing_ip
    ip_address = IPAddress.objects.create(
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/query.py", line 658, in create
    obj.save(force_insert=True, using=self.db)
  File "/opt/netbox/netbox/ipam/models/ip.py", line 884, in save
    super().save(*args, **kwargs)
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/base.py", line 814, in save
    self.save_base(
  File "/opt/netbox/lib/python3.8/site-packages/django/db/models/base.py", line 861, in save_base
    pre_save.send(
  File "/opt/netbox/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 176, in send
    return [
  File "/opt/netbox/lib/python3.8/site-packages/django/dispatch/dispatcher.py", line 177, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/vagrant/netbox-dns/netbox_dns/middleware.py", line 42, in pre_save
    check_record_permission(user, record, "netbox_dns.add_record")
  File "/vagrant/netbox-dns/netbox_dns/middleware.py", line 131, in check_record_permission
    raise PermissionDenied()
django.core.exceptions.PermissionDenied

======================================================================
FAIL: test_clear_name_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 277, in test_clear_name_existing_ip
    self.assertTrue(status.is_success(response.status_code))
AssertionError: False is not true

======================================================================
FAIL: test_create_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 55, in test_create_ip
    self.assertTrue(status.is_success(response.status_code))
AssertionError: False is not true

======================================================================
FAIL: test_create_ip_existing_dns_record (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 86, in test_create_ip_existing_dns_record
    self.assertTrue(status.is_success(response.status_code))
AssertionError: False is not true

======================================================================
FAIL: test_create_ip_missing_dns_permission (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 112, in test_create_ip_missing_dns_permission
    self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
AssertionError: 400 != 403

======================================================================
FAIL: test_modify_name_existing_ip (netbox_dns.tests.coupling.test_ip_dns_coupling.IPAddressDNSRecordCouplingTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 461, in inner
    return func(*args, **kwargs)
  File "/vagrant/netbox-dns/netbox_dns/tests/coupling/test_ip_dns_coupling.py", line 188, in test_modify_name_existing_ip
    self.assertTrue(status.is_success(response.status_code))
AssertionError: False is not true

----------------------------------------------------------------------
Ran 9 tests in 0.752s

FAILED (failures=5, errors=2)

jean1 added 2 commits October 16, 2023 13:20
Since the custom fields needed for the experimental
IPAM coupling feature are added with a management
command, they were missing in the test database.
@jean1
Copy link
Contributor Author

jean1 commented Oct 16, 2023 via email

@peteeckel
Copy link
Owner

You can run the management command from the setup method - that way you get the added benefit of testing its functionality as well.

from django.core import management

management.call_command("setup_coupling")

@peteeckel
Copy link
Owner

And don't worry about your perceived sloppiness ... the stuff is really complex, and it's easy to overlook things. I just noticed because the number of tests executed was still 381 :-)

@peteeckel peteeckel added the enhancement New feature or request label Oct 16, 2023
@peteeckel peteeckel self-assigned this Oct 16, 2023
@peteeckel peteeckel changed the base branch from main to feature/ipam-coupling October 16, 2023 15:12
@peteeckel peteeckel merged commit 17e4893 into peteeckel:feature/ipam-coupling Oct 16, 2023
@peteeckel
Copy link
Owner

Hi @jean1, I've merged your code to a feature branch now and added a couple of small commit, mostly aiming at cosmetic changes and some improvements in terms of readability.

I only found one issue that wasn't cosmetic: In netbox_dns.__init__.py you forgot to call super().ready() at the end. This leads to NetBox DNS not being loaded at all. I fixed that one.

Then, I renamed your custom fields. The problem with custom field names is that they are global, and zone and particularly name are a bit too general not to cause trouble. Now they are less easy to digest but will hopefully not clash with anyone else's names. In the GUI you can't tell the difference anyway as I added labels "Zone" and "Name".

Please have a look at the merged branch and tell me if you find anything you're not fine with. As I said, most of the changes are cosmetic and some deal with code segments that could be implemented in a more elegant and readable way. Most notably I replaced parts similar to

record_query = Record.objects.filter(ipam_ip_address=ip_address)

with

record_query = ip_address.netbox_dns_records.all()

or

record = ip_address.netbox_dns_records.first()

instead of using record_query[0] after the first expression.

I will now see what I can improve in my own code in order to take advantage of the new data when ipam_coupling has been turned on. One thing that comes to my mind is to display a link to the IPAddress object in the detail view for managed records if they have such a link, and maybe a separate tab displaying the related IPAddress objects for each zone having linked managed records. Shouldn't take too long.

Then I'll add some documentation, and then finally we get the first release with sensible IPAM integration out to the public. Again, thank you very much for your work, without it it would definitely have taken much longer!

peteeckel pushed a commit that referenced this pull request Oct 16, 2023
* Introduce an experimental IPAM-DNS coupling feature

Two new custom fields are added on IP Address :
- name
- zone

Through a middleware and signals, all IP Address creation and modification
are intercepted. Using the new custom fields, the corresponding DNS record
is created, modified or deleted accordingly.

Permission on DNS records are enforced.

The IP address "dns_name" field is also updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants