auroraresearchlab / netbox-dns Goto Github PK
View Code? Open in Web Editor NEWNetbox Dns is a netbox plugin for managing zone, nameserver and record inventory.
License: MIT License
Netbox Dns is a netbox plugin for managing zone, nameserver and record inventory.
License: MIT License
Hi. I just installed netbox-dns plugin.
After installing I run collectstatic
and migrate
commands on manage.py
, than restarted services.
Everything looks fine but there is nothing on plugins menu on Web UI.
Inside Django Admin there is a Netbox DNS section, but not in main web UI.
Netbox: 3.0.3 (fresh install)
Python 3.9.2
CentOS 8
I also have installed secretstore, Qr-code and topology-views plugins. Just to be noted.
Minor and moderate issues with filters:
Netbox: 3.0.11
Python: 3.8.11
PostgreSQL: 10.19
When i upgrade netbox, the following error occurred:
Operations to perform:
Apply all migrations: admin, auth, circuits, contenttypes, dcim, django_rq, extras, ipam, netbox_dns, sessions, taggit, tenancy, users, virtualization
Running migrations:
Applying netbox_dns.0004_create_ptr_for_a_aaaa_records...Traceback (most recent call last):
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/utils.py", line 82, in _execute
return self.cursor.execute(sql)
psycopg2.errors.ObjectInUse: cannot CREATE INDEX "netbox_dns_record" because it has pending trigger events
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/core/management/base.py", line 89, in wrapped
res = handle_func(*args, **kwargs)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/core/management/commands/migrate.py", line 244, in handle
post_migrate_state = executor.migrate(
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/migrations/executor.py", line 117, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/migrations/executor.py", line 227, in apply_migration
state = migration.apply(state, schema_editor)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/migrations/migration.py", line 126, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/migrations/operations/models.py", line 858, in database_forwards
schema_editor.add_constraint(model, self.constraint)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/base/schema.py", line 397, in add_constraint
self.execute(sql, params=None)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/base/schema.py", line 145, in execute
cursor.execute(sql, params)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/opt/netbox-3.0.11/venv/lib64/python3.8/site-packages/django/db/backends/utils.py", line 82, in _execute
return self.cursor.execute(sql)
django.db.utils.OperationalError: cannot CREATE INDEX "netbox_dns_record" because it has pending trigger events
Try to modify netbox_dns/migrations/0004_create_ptr_for_a_aaaa_records.py
, add the following on line 26
atomic = False
Run manage.py migrate
successfully.
When a zone that has A or AAAA records with automatic PTR record generation is deleted, under certain circumstances the deletion fails with the following error message:
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/template/base.py", line 848, in _resolve_lookup
raise VariableDoesNotExist("Failed lookup for key "
django.template.base.VariableDoesNotExist: Failed lookup for key [page] in <netbox_dns.tables.ZoneTable object at 0x7fe1c1a08220>
Internal Server Error: /plugins/netbox_dns/zones/delete/
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/opt/netbox/lib/python3.8/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/opt/netbox/lib/python3.8/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/opt/netbox/netbox/utilities/views.py", line 93, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/opt/netbox/lib/python3.8/site-packages/django/views/generic/base.py", line 98, in dispatch
return handler(request, *args, **kwargs)
File "/opt/netbox/netbox/netbox/views/generic.py", line 1039, in post
obj.delete()
File "/opt/netbox/lib/python3.8/site-packages/netbox_dns/models.py", line 255, in delete
record.update_ptr_record()
File "/opt/netbox/lib/python3.8/site-packages/netbox_dns/models.py", line 453, in update_ptr_record
super().save()
File "/opt/netbox/lib/python3.8/site-packages/django/db/models/base.py", line 682, in save
self._prepare_related_fields_for_save(operation_name='save')
File "/opt/netbox/lib/python3.8/site-packages/django/db/models/base.py", line 932, in _prepare_related_fields_for_save
raise ValueError(
ValueError: save() prohibited to prevent data loss due to unsaved related object 'zone'.
Exception while resolving variable 'request' in template 'home.html'.
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/template/base.py", line 829, in _resolve_lookup
current = current[bit]
File "/opt/netbox/lib/python3.8/site-packages/django/template/context.py", line 83, in __getitem__
raise KeyError(key)
KeyError: 'request'
So far, I was only able to reproduce it in a development version of the plugin containing additional features, but the underlying bug is in the existing code in version 0.6.0.
While currently of limited functionality (though it does come in handy when assigning tags), it would be useful to have the BulkEdit functionality available for NameServer objects, too - currently there is only BulkDelete.
Following up on discussion #107, the zone status field needs a bit of attention.
The notion of a "passive" zone does not make much sense in the given context, and there are some other states that make sense, so the list of states a zone can have should be extended, e.g. to
When a zone is not marked "Active", this should have an impact on the creation of PTR records if there are any address records in the zone. At least they should get flagged as inactive so that provisioning mechanisms based on Netbox DNS data can handle them appropriately (probably just ignoring them).
Hello.
plugin doesn't work on version 3.1.1
<class 'django.urls.exceptions.NoReverseMatch'>
'netbox_dns' is not a registered namespace inside 'plugins'
Python version: 3.8.10
NetBox version: 3.1.1
And it fails on manage.py migrate
../venv/bin/python manage.py migrate
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/base.py", line 89, in wrapped
res = handle_func(*args, **kwargs)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/commands/migrate.py", line 75, in handle
self.check(databases=[database])
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/management/base.py", line 419, in check
all_issues = checks.run_checks(
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/checks/registry.py", line 76, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/checks/urls.py", line 13, in check_url_config
return check_resolver(resolver)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/core/checks/urls.py", line 23, in check_resolver
return check_method()
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 416, in check
for pattern in self.url_patterns:
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 602, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/urls/resolvers.py", line 595, in urlconf_module
return import_module(self.urlconf_name)
File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 848, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/opt/netbox-3.1.1/netbox/netbox/urls.py", line 9, in <module>
from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_api_patterns
File "/opt/netbox-3.1.1/netbox/extras/plugins/urls.py", line 28, in <module>
urlpatterns = import_object(f"{plugin_path}.urls.urlpatterns")
File "/opt/netbox-3.1.1/netbox/extras/plugins/utils.py", line 31, in import_object
spec.loader.exec_module(module)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/netbox_dns/urls.py", line 5, in <module>
from .views import (
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/netbox_dns/views.py", line 3, in <module>
from netbox_dns.forms import (
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/netbox_dns/forms.py", line 37, in <module>
class ZoneForm(BootstrapMixin, CustomFieldModelForm):
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/forms/models.py", line 226, in __new__
new_class = super().__new__(mcs, name, bases, attrs)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/forms/forms.py", line 31, in __new__
new_class = super().__new__(mcs, name, bases, attrs)
File "/opt/netbox-3.1.1/venv/lib/python3.8/site-packages/django/forms/widgets.py", line 191, in __new__
new_class = super().__new__(mcs, name, bases, attrs)
TypeError: Cannot create a consistent method resolution
order (MRO) for bases BootstrapMixin, CustomFieldModelForm
Generating the PTR records for A/AAAA records automatically is a critical feature for DNS operation and must work reliably, so specific tests are required to ensure the mechanism doesn't break, especially with later updates to the plugin. So a suite of unit tests should be provided.
It would be nice to see which zones are associated with the name server at the Name Servers view.
Also, to associate a Name Server to devices and VMs. Or even with services already described on device/VM, so we know where it is and in which IP address it responds.
Another sensible addition would affect the issue of SOA records.
There needs to be exactly one SOA record per zone, and their contents is structured:
IMHO it would make sense to make the entry of these data mandatory when creating a zone (apart from "SERIAL", which I'll cover later), use separate input fields for them and validate the data put into them, so that the maintenance of the field would be simplified.
[edit: Actually the alternative forms such as "1w" are not in the RFC, so we can limit this to entries in seconds to make life simpler for a start]
For the SERIAL field, multiple ways of handling them would be reasonable: If netbox-dns would be used as the primary source of the zone data it would make sense to generate them using a monotonously increasing serial number along one of the usual schemes such as yyyymmddxx or seconds since the epoch.
Another enhancement suggestion:
It would be helpful to be able to define a default TTL per zone in the zone definitions, so that all records defined in that zone will default to that TTL (but be overrideable).
In some list views (e.g. "Records"), when more than one item is selected the "Edit All" and "Delete All" buttons don't show up even if all permissions have been granted and the "Select all ... items" check box is checked.
The problem turns out to be the consequence of using the "validated_viewname" template tag instead of "plugin_validated_viewname". This was also the real cause of #87, fixed by simply hard-coding the view names (which is OK with model-specific templates, but not in general).
Great start of the plugin. Could you add the configuration to your README.md?
Installation
$ source /opt/netbox/venv/bin/activate
(venv) $ pip install netbox-dns
Configuration
Add the plugin to the NetBox config. ~/netbox/configuration.py
PLUGINS = [
'netbox_dns',
]
Full reference:
https://netbox.readthedocs.io/en/stable/plugins/
Obviously an oversight by myself: When multiple zones are selected, it is not possible to edit the SOA MNAME (primary name server) field for all of them because the related field is missing from the form.
Oops.
The zone table in the nameserver detail view is the only table still not using django_tables2. Unfortunately I messed this up myself in PR #43.
The table should be using the standard rendering library so that features like quick search and column configuration work.
While working with the Ansible lookup plugin for Netbox, I found that it's not possible to filter records by the zone they are belonging to. While not strictly necessary it is, especially when there are lots of records in the database, desirable to restrict the list of records retrieved from Netbox so the amount of data stays manageable.
When the API is used to build zone files, the canonical way of doing that would be to loop over all zones and then retrieve all records per zone to populate the zone file.
Trying to use the "Quick search" box in the Records list, but nothing happens.
Actually, I don't see any REST request sent, nor Javascript errors in the browser console (Chrome).
Branch netbox32-changes
I know @jeremystretch already mentioned that in his PR #128, but since that one is closed I would rather raise a separate issue so it's not forgotten.
As there is currently no supported way to inhibit the edit/delete buttons for objects that can't be edited or deleted, some strange behaviour is taking place in the "Managed Records" list views.
/plugins/netbox-dns/records/27/edit/
The requested page does not exist.
or, for "Delete":
/plugins/netbox-dns/records/27/delete/
The requested page does not exist.
I expect all of these issues to go away as soon as there is a mechanism that allows to disable the edit/delete functionality in object lists.
SOA records are created automatically from the zone SOA data. Provide a test suite that covers the correctness of the SOA data both on initial creation and on modifications made to the zone data later on.
I just realised that the SOA_MNAME and SOA_RNAME entries in the generated SOA record need to end with a dot, otherwise the name server will append the current origin to them, which is obviously wrong.
Currently they end with a dot when the NS name/SOA_MNAME data is added with a dot, otherwise it will incorrectly not have a dot at the end. This should be fixed.
While investigating #36, I initially thought that tests might keep failing because of an issue with the test data and my new validation code from PR #35. Specifically, "[00:00]" is not a valid IPv6 address, and "value 2" also does not parse as an IPv4 address in all likelihood.
Unfortunately this was not the reason for the failing tests after all, but whatever ... PR follows shortly.
It seems either the new Netbox version 3.1.0 or one of its prerequisites is incompatible with Netbox DNS.
When trying to run manage.py makemigrations
I get a long dump:
(netbox) [root@dns netbox]# /opt/netbox/netbox/manage.py makemigrations
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 419, in execute_from_command_line
utility.execute()
File "/opt/netbox/lib/python3.8/site-packages/django/core/management/__init__.py", line 413, 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 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/netbox/lib/python3.8/site-packages/django/core/management/base.py", line 393, in execute
self.check()
File "/opt/netbox/lib/python3.8/site-packages/django/core/management/base.py", line 419, in check
all_issues = checks.run_checks(
File "/opt/netbox/lib/python3.8/site-packages/django/core/checks/registry.py", line 76, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
File "/opt/netbox/lib/python3.8/site-packages/django/core/checks/urls.py", line 13, in check_url_config
return check_resolver(resolver)
File "/opt/netbox/lib/python3.8/site-packages/django/core/checks/urls.py", line 23, in check_resolver
return check_method()
File "/opt/netbox/lib/python3.8/site-packages/django/urls/resolvers.py", line 412, in check
for pattern in self.url_patterns:
File "/opt/netbox/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/opt/netbox/lib/python3.8/site-packages/django/urls/resolvers.py", line 598, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/opt/netbox/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/opt/netbox/lib/python3.8/site-packages/django/urls/resolvers.py", line 591, in urlconf_module
return import_module(self.urlconf_name)
File "/opt/netbox/lib64/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 783, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/opt/netbox/netbox/netbox/urls.py", line 9, in <module>
from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_api_patterns
File "/opt/netbox/netbox/extras/plugins/urls.py", line 28, in <module>
urlpatterns = import_object(f"{plugin_path}.urls.urlpatterns")
File "/opt/netbox/netbox/extras/plugins/utils.py", line 31, in import_object
spec.loader.exec_module(module)
File "/opt/netbox/lib/python3.8/site-packages/netbox_dns/urls.py", line 5, in <module>
from .views import (
File "/opt/netbox/lib/python3.8/site-packages/netbox_dns/views.py", line 3, in <module>
from netbox_dns.forms import (
File "/opt/netbox/lib/python3.8/site-packages/netbox_dns/forms.py", line 37, in <module>
class ZoneForm(BootstrapMixin, CustomFieldModelForm):
File "/opt/netbox/lib/python3.8/site-packages/django/forms/models.py", line 226, in __new__
new_class = super().__new__(mcs, name, bases, attrs)
File "/opt/netbox/lib/python3.8/site-packages/django/forms/forms.py", line 31, in __new__
new_class = super().__new__(mcs, name, bases, attrs)
File "/opt/netbox/lib/python3.8/site-packages/django/forms/widgets.py", line 191, in __new__
new_class = super().__new__(mcs, name, bases, attrs)
TypeError: Cannot create a consistent method resolution
order (MRO) for bases BootstrapMixin, CustomFieldModelForm
Some classes in Beta 2 are different from Beta 1 (new class names, some new functionality):
NetBoxModelSerializer
replaces PrimaryModelSerializer
NetBoxModelViewSet
replaces ModelViewSet
NetBoxRouter
replaces OrderedDefaultRouter
The code needs to be adjusted accordingly.
When creating a zone via the "+" button or the "Add" button in the Zone list view, defaults can be provided for almost all field except Nameservers and SOA MName, which always have to be entered manually.
Defaults should be definable for these fields as well.
When entering a search string in the "Quick Search" field for NameServer objects, not filtering takes place at all.
Zones with names ending on in-addr.arpa
or ip6.arpa
get some special handing because in most cases they contain automatically generated PTR records for A and AAAA records. In most cases that is not an issue as only records within that zone are affected, but there is a case that has some potential for improvement.
If A reverse zone is created or renamed, that special handling consists in finding out which A or AAAA records in the system have values that need to be inserted in the new reverse zone, or migrated from other reverse zones they are currently in (this is the case when a PTR was residing e.g. in zone y.z.in-addr.arpa
and now a new zone x.y.z.in-addr.arpa
gets created or renamed to from a different name where the record now belongs).
Currently, the process of finding out which address records are to be considered for having their PTR record added to the new or renamed zone is involving looking at all address records that don't have PTR generation disabled. This works, but when there are a lot of A/AAAA records in Netbox DNS it is getting slow, also because the process of finding a matching reverse zone is not completely trivial. If there are a couple of thousand A/AAAA records to consider, the fact that processing time increases linearly with the number of records in the database leads to inacceptable performance.
As outlined in discussion #64, there should be an option to create the SOA Serial number automatically on zone updates.
Every time a change to a zone is made (either to the zone itself, e.g. the SOA record of the zone, or to its records) the serial number in the SOA SERIAL field needs to be updated in order for DNS secondary servers to pick up the change and perform an IXFR/AXFR from their master.
Especially when PTR records are generated automatically, keeping track of which serial numbers need to be increased can be difficult because there may be multiple IPv4 and/or IPv6 PTR zones might me affected by changed A/AAAA records in one zone.
The proposed enhancement should take care of which zones have changed and only advance the serial numbers of zones that actually have changes, lest an unnecessary load might be put on the DNS infrastructure.
We use external and internal views in BIND for the same zones, as many other people do.
For example, when we are inside the LAN, a host record like 'host1.example.com` points to a some local IP like 192.168.1.1.
The same record 'host1.example.com' when it get queried from external network, points to some real external IP like 195.XXX.XXX.XXX
https://www.cyberciti.biz/faq/linux-unix-bind9-named-configure-views/
Please allow the same zones but with different "view" types or something like that.
While testing the changes for PR #35, I noticed that some of the tests for netbox_dns fail:
(netbox) [root@dns netbox-dns]# /opt/netbox/netbox/manage.py test netbox_dns
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
......................................F....F......................F....F......................F....F....
======================================================================
FAIL: test_get_object_anonymous (netbox_dns.tests.test_views.NameServerTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 387, in inner
return func(*args, **kwargs)
File "/opt/netbox/netbox/utilities/testing/views.py", line 62, in test_get_object_anonymous
self.assertHttpStatus(response, 200)
File "/opt/netbox/netbox/utilities/testing/base.py", line 68, in assertHttpStatus
self.assertEqual(response.status_code, expected_status, err_message)
AssertionError: 302 != 200 : Expected HTTP status 200; received 302: No data
======================================================================
FAIL: test_list_objects_anonymous (netbox_dns.tests.test_views.NameServerTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 387, in inner
return func(*args, **kwargs)
File "/opt/netbox/netbox/utilities/testing/views.py", line 401, in test_list_objects_anonymous
self.assertHttpStatus(response, 200)
File "/opt/netbox/netbox/utilities/testing/base.py", line 68, in assertHttpStatus
self.assertEqual(response.status_code, expected_status, err_message)
AssertionError: 302 != 200 : Expected HTTP status 200; received 302: No data
======================================================================
FAIL: test_get_object_anonymous (netbox_dns.tests.test_views.RecordTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 387, in inner
return func(*args, **kwargs)
File "/opt/netbox/netbox/utilities/testing/views.py", line 62, in test_get_object_anonymous
self.assertHttpStatus(response, 200)
File "/opt/netbox/netbox/utilities/testing/base.py", line 68, in assertHttpStatus
self.assertEqual(response.status_code, expected_status, err_message)
AssertionError: 302 != 200 : Expected HTTP status 200; received 302: No data
======================================================================
FAIL: test_list_objects_anonymous (netbox_dns.tests.test_views.RecordTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 387, in inner
return func(*args, **kwargs)
File "/opt/netbox/netbox/utilities/testing/views.py", line 401, in test_list_objects_anonymous
self.assertHttpStatus(response, 200)
File "/opt/netbox/netbox/utilities/testing/base.py", line 68, in assertHttpStatus
self.assertEqual(response.status_code, expected_status, err_message)
AssertionError: 302 != 200 : Expected HTTP status 200; received 302: No data
======================================================================
FAIL: test_get_object_anonymous (netbox_dns.tests.test_views.ZoneTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 387, in inner
return func(*args, **kwargs)
File "/opt/netbox/netbox/utilities/testing/views.py", line 62, in test_get_object_anonymous
self.assertHttpStatus(response, 200)
File "/opt/netbox/netbox/utilities/testing/base.py", line 68, in assertHttpStatus
self.assertEqual(response.status_code, expected_status, err_message)
AssertionError: 302 != 200 : Expected HTTP status 200; received 302: No data
======================================================================
FAIL: test_list_objects_anonymous (netbox_dns.tests.test_views.ZoneTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/netbox/lib/python3.8/site-packages/django/test/utils.py", line 387, in inner
return func(*args, **kwargs)
File "/opt/netbox/netbox/utilities/testing/views.py", line 401, in test_list_objects_anonymous
self.assertHttpStatus(response, 200)
File "/opt/netbox/netbox/utilities/testing/base.py", line 68, in assertHttpStatus
self.assertEqual(response.status_code, expected_status, err_message)
AssertionError: 302 != 200 : Expected HTTP status 200; received 302: No data
----------------------------------------------------------------------
Ran 104 tests in 5.102s
FAILED (failures=6)
Destroying test database for alias 'default'...
Unfortunately, it took me a while to find out that this was not due to my changes, but the tests also fail for the current main branch in exactly the same way.
This seems to be because the Netbox ViewTestCases "GetObjectViewTestCase" and "ListObjectsViewTestCase" fail for anonymous access, possibly because the views return an HTTP response code 302 instead of 200 in this case. I haven't dug any deeper yet, but will investigate when I find the time.
Would import export (bind) zone files be an option in the future ?
Also, now it could be cool to have an deploy button which uses netbox source to deploy DNS records to bind servers :-)
Just saying and wishing.
So far thanks for this great work
Hiya there,
I've had some issues accessing all web pages in Netbox, due to an error regarding inc/table_controls.html
not existing.
I can successfully load pages such as 'zones' and 'nameservers' when copying to inc/table_controls.html
via
cd /opt/netbox/netbox/templates/inc; cp table_controls_htmx.html table_controls.html
So it seems this plugin should reference table_controls_htmx.html
, rather then table_controls.html
It would be a useful feature to maintain the NS records for the name servers defined for a zone automatically. Details are in the discussion I opened in #63.
When a name server is defined for a zone and the zone the name server is located in is within the data maintained in NetBox DNS, it should be verified that there actually is an address record in the zone the name server belongs to. External name servers can't be checked, so there should be no warning for them.
As the resolution of a name server's name is depending on which view a zone belongs to, this needs to be checked on zone level, not on the name server level.
As pointed out by @jeroenvermeulen, matches for the name field in the API shoule be exact, not partial, so that it's possible to search for an exact record.
Furthermore, API and GUI filters for all name and value fields for records as well as names for name servers and zones should be exact as well. For case insensitive/partial searches, the filters can be modified in the API, and the "search" field can be used in the GUI, so no functionality is lost by changing that.
This is probably more a long-term project than something that can be implemented in a singe PR.
In the IPAM module there are lots of IP address data, together with an optional DNS name. This is exactly the information that is maintained in the DNS module as well with a different focus. It would be very useful to provide some kind of link between the two in some way that probably needs to be discussed further.
Some ideas:
I did not dig into the Netbox code base too deeply yet, so I'm not sure whether a plugin can change the behaviour of a core module (which would be necessary for some of the functionality sketched above), or if a cross-referece to data from a core module is possible at all from a plugin, but it would be really nice to have.
Another issue is that IP addresses are not necessarily in a 1-1 relation to DNS records if different VRFs or different DNS views (BIND jargon) are in use, so that one IPAM IP address might be present in different zones/views. This is something that probably needs some discussion.
Hiya there,
Currently I'm writing a python script to interpolate between the PowerDNS API and the Netbox API, while troubleshooting some API call issues, looking at the Netbox API documentation, adding zones via an API call via POST specifies the following
soa_mname
integer
title: SOA MName
The MNAME should be a string, not an integer, as per the MNAME listed in https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-soa-record/
There would be no circumstances an SOA MNAME contained within the rrset returned would ever be an integer, so this type should be changed.
One really challenging issue with maintaining zone data is to keep the reverse resolution zones in-addr.arpa. and ip6.arpa. consistent with the forward zones.
In one of the DNS environments I maintain I do this using Ansible with a YAML file defining the zone data, some simple playbooks, a custom Ansible module and some Jinja 2-Templates creating the forward and reverse zones for IPv4 and IPv6, respectively, from that single source of data. Provided that the DNS module has all the zone data, it should be possible to create the reverse zones from the existing zone data internally as well.
There are some special cases which I managed using flags for the entries in the YAML file, and which would similarly be required for the automatic zone generation, specifically two booleans that tell the converter not to create IPv4 and/or IPv6 PTR records for a specific address, but in general the generation of the PTR records can be automated quite easily.
An implementation idea would be to create the reverse zones manually in the DNS plugin, providing a "Automatic Provisioning" flag that tells the plugin to automatically generate PTR records from A/AAAA records in the forward zones (of the same view, once that feature is implemented). The option to add some other records manually (i.e. for host names not in one of the locally administered zones) is necessary as well.
Currently it is possible to enter malformed data i.e. in the A and AAAA fields.
Using Python's ipaddr module it should be easy to detect and reject "IP addresses" like "192.168.1.300" or "this.is.not.an.ip.address", which are not allowed for address records. For other records such as TXT, CNAME it's not that simple, but in some cases validation should be possible as well (such as CNAME, which should be a valid name and occur only once).
First of all, thank you for this plugin!!
I have been looking for a way to document various DNS records, trying to desparately avoid using a spreadsheet, and keeping it together with NetBox is perfect.
Would it be possible to add support for SRV record type?
Thanks in advance.
zone1.example.com
0.0.10.in-addr.arpa
zone,type,name,value,disable_ptr
zone1.example.com,A,clash1,10.0.0.10,true
zone1.example.com,A,clash2,10.0.0.10,true
zone1.example.com,A,clash3,10.0.0.10,true
An error message is shown with the information that there were multiple A/AAAA records mapped to the same address with PTR enabled.
<class 'django.db.utils.IntegrityError'>
duplicate key value violates unique constraint "unique_pointer_for_address"
DETAIL: Key (type, value)=(A, 10.0.0.10) already exists.
Python version: 3.8.11
NetBox version: 3.2.0-beta1
Multiple A or AAAA records can point to the same IPv4 or IPv6 address, provided that there is either no PTR zone containing records pointing back from the address to the name, or all but at most one A/AAAA records have PTR generation disabled. The latter is the case when the above test data is imported (in a variation one could also set one of the "Disable PTR" values to False).
Setting all records' "Disable PTR" field to "False" should be caught earlier than when NetBox tries to insert the inconsistent data into the database, which is causing the exception.
Working on the NetBox DNS code gets increasingly difficult because the files filters.py
, forms.py
etc. have grown in size over the last months, which makes them hard to maintain.
I suggest splitting them into smaller files wherever possible. Unfortunately, models.py
still resists this approach because of the dependencies between the models, which would lead to the notirious circular import problem, but splitting the rest of the files is pretty straightforward.
Hi,
we have a problem.
I was just trying to use the Ansible Netbox plugin to fetch data from netbox_dns.
Apart from some pretty strange bugs in the Ansible plugin itself (which are not part of this problem), it uses the pynetbox Python module to access Netbox. And here's where the trouble starts.
When pynetbox creates an endpoint object to access Netbox, it rewrites the application name so that underscores are converted to dashes in the URL. So, to access, for example, nameservers, it constructs the API URL as follows: https://netbox.example.com/api/plugins/netbox-dns/nameservers/
which obviously will not work, as the real URL is https://netbox.example.com/api/plugins/netbox_dns/nameservers/
.
This behaviour is hard-coded in pynetbox/core/endpoint.py
:
def __init__(self, api, app, name, model=None):
self.return_obj = self._lookup_ret_obj(name, model)
self.name = name.replace("_", "-") <----
self.api = api
self.base_url = api.base_url
self.token = api.token
self.session_key = api.session_key
self.url = "{base_url}/{app}/{endpoint}".format(
base_url=self.base_url, app=app.name, endpoint=self.name,
)
self._choices = None
To really get rid of this it's probably necessary to change the URL schema so that it uses a dash instead of an underscore.
While not strictly forbidden, there are several recommendations around against using underscores in URLs (e.g. here, Caution: Google link), and this seems to be one of the occasions where it really bites.
Another enhancement that I detected missing when I tried starting to actually work with the plugin.
When records are imported via CSV, the "disable_ptr" flag is not available as an importable field. It would however be really useful to be able to specify it in CSV.
django.db.utils.ProgrammingError: column netbox_dns_zone.soa_serial_auto does not exist
<class 'django.db.utils.ProgrammingError'>
column netbox_dns_zone.soa_serial_auto does not exist
LINE 1: ...e"."soa_expire", "netbox_dns_zone"."soa_minimum", "netbox_dn...
Python version: 3.8.10
NetBox version: 3.1.1
When a zone is edited, the values for nameservers
and soa_mname
are always taken from the default settings (if there are any) instead of from the current settings of the zone.
I found an interesting bug when I tested some of my new functionality. It is not possible to asssign zones with the RecordBulkEdit form.
name
ns1.example.com
ns2.example.com
name,status
zone1.example.com,active
zone2.example.com,active
zone3.example.com,active
zone4.example.com,active
zone5.example.com,active
zone6.example.com,active
zone7.example.com,active
zone8.example.com,active
zone9.example.com,active
zone,type,name,value
zone1.example.com,A,name1,10.0.1.1
zone1.example.com,A,name2,10.0.1.2
zone1.example.com,A,name3,10.0.1.3
zone1.example.com,A,name4,10.0.1.4
zone1.example.com,A,name5,10.0.1.5
zone1.example.com,A,name6,10.0.1.6
zone2.example.com,A,name1,10.0.2.1
zone2.example.com,A,name2,10.0.2.2
zone2.example.com,A,name3,10.0.2.3
zone2.example.com,A,name4,10.0.2.4
zone2.example.com,A,name5,10.0.2.5
zone2.example.com,A,name6,10.0.2.6
zone3.example.com,A,name1,10.0.3.1
zone3.example.com,A,name2,10.0.3.2
zone3.example.com,A,name3,10.0.3.3
zone3.example.com,A,name4,10.0.3.4
zone3.example.com,A,name5,10.0.3.5
zone3.example.com,A,name6,10.0.3.6
The list of available zones is empty.
The list should contain the zones imported as test data.
Generally in a reverse zone there can't be any A/AAAA records and in a non-reverse zone there can't be any PTR records.
To improve the reliability of the system, creating records of the wrong type should be inhibited on the form and/or model level. Some other record types (e.g. MX) will also be affected by the same restrictions on PTR zones.
After new PRs merged I see there is a missing migration.
$ python3 manage.py makemigrations
Migrations for 'netbox_dns':
/home/ausec/Dev/netbox-dns/netbox_dns/migrations/0007_alter_zone_soa_serial_auto.py
- Alter field soa_serial_auto on zone
Here is the content of 0007_alter_zone_soa_serial_auto.py
# Generated by Django 3.2.9 on 2021-12-13 13:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('netbox_dns', '0006_zone_soa_serial_auto'),
]
operations = [
migrations.AlterField(
model_name='zone',
name='soa_serial_auto',
field=models.BooleanField(default=True),
),
]
Investigating this issue I see that it might be related to PR #74.
Here are the added lines (135 - 139) to models.py
in this PR
soa_serial_auto = models.BooleanField(
verbose_name="Generate SOA Serial",
help_text="Automatically generate the SOA Serial field",
default=True,
)
Here is the result migration. Lines 14 - 18.
....
operations = [
migrations.AddField(
model_name="zone",
name="soa_serial_auto",
field=models.BooleanField(default=False),
preserve_default=False,
),
....
default "true" value not reflected in the migration file.
If I am missing something, please let me know
When testing the NetBox DNS plugin with NetBox 3.2 beta 1 I ran into an error clicking on "Change Log" in any of the list views.
(NetBox "feature" branch, NetBox DNS "netbox32-changes" branch)
'view_helpers' is not a registered tag library. Must be one of:
admin_list
admin_modify
admin_urls
builtins.filters
builtins.tags
buttons
cache
custom_links
django_rq
django_tables2
form_helpers
helpers
humanize
i18n
jquery_path
l10n
log
log_levels
mptt_admin
mptt_tags
navigation
perms
plugins
rest_framework
search
static
tz
During tests for issue #117 I found that some functionality is lacking in the API.
When a zone is created, it is not possible to add name servers to it by populating the "nameservers" field in the JSON data passed to the API. Instead of creating the nameservers, there is an error message that the standard serualizer's create()
method cannot handle nested objects:
The `.create()` method does not support writable nested fields by default.
A similar issue pops up when trying to update the list of name servers using the API:
The `.update()` method does not support writable nested fields by default.
Both functionalities are needed for the API to be used in a sensible way to import data from other systems.
When the number of records configured to be displayed per page is smaller than the number of records available in the zone view, switching to the "Records" tab causes an error:
This can be worked around by modifying the number of displays, as it only occurs when more than one page is to be displayed according to the paginator settings.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.