netbox-ddns 1.2.9__tar.gz → 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netbox-ddns-1.2.9/netbox_ddns.egg-info → netbox_ddns-1.4.0}/PKG-INFO +8 -2
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/README.md +6 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/__init__.py +4 -4
- netbox_ddns-1.4.0/netbox_ddns/api/serializers.py +17 -0
- netbox_ddns-1.4.0/netbox_ddns/api/urls.py +10 -0
- netbox_ddns-1.4.0/netbox_ddns/api/views.py +10 -0
- netbox_ddns-1.4.0/netbox_ddns/filtersets.py +8 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/forms.py +1 -2
- netbox_ddns-1.4.0/netbox_ddns/migrations/0009_alter_dnsstatus_id_alter_extradnsname_id_and_more.py +38 -0
- netbox_ddns-1.4.0/netbox_ddns/migrations/0010_extradnsname_created_extradnsname_custom_field_data_and_more.py +36 -0
- netbox_ddns-1.4.0/netbox_ddns/migrations/__init__.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/models.py +3 -3
- netbox_ddns-1.4.0/netbox_ddns/search.py +10 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/tables.py +5 -5
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/template_content.py +1 -1
- netbox_ddns-1.4.0/netbox_ddns/templates/netbox_ddns/extradnsname.html +169 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/templates/netbox_ddns/ipaddress/dns_extra.html +1 -1
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/templates/netbox_ddns/ipaddress/dns_info.html +3 -1
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/templates/netbox_ddns/ipaddress/dns_refresh_button.html +1 -1
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/urls.py +5 -1
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/views.py +43 -2
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0/netbox_ddns.egg-info}/PKG-INFO +8 -2
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns.egg-info/SOURCES.txt +9 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/setup.cfg +1 -1
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/LICENSE.txt +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/MANIFEST.in +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/admin.py +0 -0
- {netbox-ddns-1.2.9/netbox_ddns/migrations → netbox_ddns-1.4.0/netbox_ddns/api}/__init__.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/background_tasks.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0001_initial.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0002_add_ttl.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0003_dnsstatus.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0004_ensure_trailing_dot.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0005_extradnsname.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0006_extradns_cname.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0007_zone_meta.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/migrations/0008_server_server_port.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/signals.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/utils.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/validators.py +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns.egg-info/dependency_links.txt +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns.egg-info/not-zip-safe +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns.egg-info/requires.txt +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns.egg-info/top_level.txt +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/pyproject.toml +0 -0
- {netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-ddns
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Dynamic DNS Connector for NetBox
|
|
5
5
|
Home-page: https://github.com/sjm-steffann/netbox-ddns
|
|
6
6
|
Author: Sander Steffann
|
|
@@ -12,7 +12,7 @@ Classifier: Framework :: Django :: 3.0
|
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.6
|
|
15
|
-
Requires-Python: >=3.
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE.txt
|
|
18
18
|
Requires-Dist: setuptools
|
|
@@ -33,6 +33,12 @@ For now all configuration is done in the NetBox admin back-end. A later version
|
|
|
33
33
|
|
|
34
34
|
This plugin in compatible with [NetBox](https://netbox.readthedocs.org/) v3.0.0 and greater, support for Netbox v2.11.0 is dropped in v1.1.4 due to UI implementation.
|
|
35
35
|
|
|
36
|
+
> [!Important]
|
|
37
|
+
> Netbox 4.0 - Admin interface disabled by default<br />
|
|
38
|
+
> Can be re-enabled by specifying `DJANGO_ADMIN_ENABLED = True` in `configuration.py`<br />
|
|
39
|
+
> If static files are not loaded, re-run `upgrade.sh` this will copy back the required static assets.
|
|
40
|
+
|
|
41
|
+
|
|
36
42
|
## Installation
|
|
37
43
|
|
|
38
44
|
First, add `netbox-ddns` to your `/opt/netbox/local_requirements.txt` file. Create it if it doesn't exist.
|
|
@@ -13,6 +13,12 @@ For now all configuration is done in the NetBox admin back-end. A later version
|
|
|
13
13
|
|
|
14
14
|
This plugin in compatible with [NetBox](https://netbox.readthedocs.org/) v3.0.0 and greater, support for Netbox v2.11.0 is dropped in v1.1.4 due to UI implementation.
|
|
15
15
|
|
|
16
|
+
> [!Important]
|
|
17
|
+
> Netbox 4.0 - Admin interface disabled by default<br />
|
|
18
|
+
> Can be re-enabled by specifying `DJANGO_ADMIN_ENABLED = True` in `configuration.py`<br />
|
|
19
|
+
> If static files are not loaded, re-run `upgrade.sh` this will copy back the required static assets.
|
|
20
|
+
|
|
21
|
+
|
|
16
22
|
## Installation
|
|
17
23
|
|
|
18
24
|
First, add `netbox-ddns` to your `/opt/netbox/local_requirements.txt` file. Create it if it doesn't exist.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
VERSION = '1.
|
|
1
|
+
VERSION = '1.4.0'
|
|
2
2
|
|
|
3
3
|
try:
|
|
4
|
-
from
|
|
4
|
+
from netbox.plugins import PluginConfig
|
|
5
5
|
except ImportError:
|
|
6
6
|
# Dummy for when importing outside of netbox
|
|
7
7
|
class PluginConfig:
|
|
@@ -12,8 +12,8 @@ class NetBoxDDNSConfig(PluginConfig):
|
|
|
12
12
|
name = 'netbox_ddns'
|
|
13
13
|
verbose_name = 'Dynamic DNS'
|
|
14
14
|
version = VERSION
|
|
15
|
-
min_version = '
|
|
16
|
-
max_version = '
|
|
15
|
+
min_version = '4.0.0'
|
|
16
|
+
max_version = '4.1.999'
|
|
17
17
|
author = 'Sander Steffann'
|
|
18
18
|
author_email = 'sander@steffann.nl'
|
|
19
19
|
description = 'Dynamic DNS Connector for NetBox'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from rest_framework import serializers
|
|
2
|
+
from rest_framework.relations import PrimaryKeyRelatedField
|
|
3
|
+
from ipam.models import IPAddress
|
|
4
|
+
from netbox.api.serializers import NetBoxModelSerializer
|
|
5
|
+
from ..models import ExtraDNSName
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ExtraDNSNameSerializer(NetBoxModelSerializer):
|
|
9
|
+
url = serializers.HyperlinkedIdentityField(
|
|
10
|
+
view_name='plugins-api:netbox_ddns-api:extradnsname-detail'
|
|
11
|
+
)
|
|
12
|
+
ip_address = PrimaryKeyRelatedField(queryset=IPAddress.objects.all(),)
|
|
13
|
+
|
|
14
|
+
class Meta:
|
|
15
|
+
model = ExtraDNSName
|
|
16
|
+
fields = ('id', 'ip_address', 'name', 'url')
|
|
17
|
+
read_only_fields = ('id', 'url')
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from netbox.api.viewsets import NetBoxModelViewSet
|
|
2
|
+
from ..filtersets import ExtraDNSNameFilterSet
|
|
3
|
+
from ..models import ExtraDNSName
|
|
4
|
+
from .serializers import ExtraDNSNameSerializer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ExtraDNSNameViewSet(NetBoxModelViewSet):
|
|
8
|
+
queryset = ExtraDNSName.objects.all()
|
|
9
|
+
serializer_class = ExtraDNSNameSerializer
|
|
10
|
+
filterset_class = ExtraDNSNameFilterSet
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from django import forms
|
|
2
2
|
|
|
3
3
|
from netbox_ddns.models import ExtraDNSName
|
|
4
|
-
from utilities.forms import BootstrapMixin
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
class ExtraDNSNameEditForm(
|
|
6
|
+
class ExtraDNSNameEditForm(forms.ModelForm):
|
|
8
7
|
class Meta:
|
|
9
8
|
model = ExtraDNSName
|
|
10
9
|
fields = ['name']
|
netbox_ddns-1.4.0/netbox_ddns/migrations/0009_alter_dnsstatus_id_alter_extradnsname_id_and_more.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Generated by Django 5.0.9 on 2024-11-11 17:12
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('netbox_ddns', '0008_server_server_port'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='dnsstatus',
|
|
15
|
+
name='id',
|
|
16
|
+
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterField(
|
|
19
|
+
model_name='extradnsname',
|
|
20
|
+
name='id',
|
|
21
|
+
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
|
22
|
+
),
|
|
23
|
+
migrations.AlterField(
|
|
24
|
+
model_name='reversezone',
|
|
25
|
+
name='id',
|
|
26
|
+
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
|
27
|
+
),
|
|
28
|
+
migrations.AlterField(
|
|
29
|
+
model_name='server',
|
|
30
|
+
name='id',
|
|
31
|
+
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
|
32
|
+
),
|
|
33
|
+
migrations.AlterField(
|
|
34
|
+
model_name='zone',
|
|
35
|
+
name='id',
|
|
36
|
+
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
|
37
|
+
),
|
|
38
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Generated by Django 5.0.9 on 2024-11-11 17:14
|
|
2
|
+
|
|
3
|
+
import taggit.managers
|
|
4
|
+
import utilities.json
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('extras', '0121_customfield_related_object_filter'),
|
|
12
|
+
('netbox_ddns', '0009_alter_dnsstatus_id_alter_extradnsname_id_and_more'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.AddField(
|
|
17
|
+
model_name='extradnsname',
|
|
18
|
+
name='created',
|
|
19
|
+
field=models.DateTimeField(auto_now_add=True, null=True),
|
|
20
|
+
),
|
|
21
|
+
migrations.AddField(
|
|
22
|
+
model_name='extradnsname',
|
|
23
|
+
name='custom_field_data',
|
|
24
|
+
field=models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder),
|
|
25
|
+
),
|
|
26
|
+
migrations.AddField(
|
|
27
|
+
model_name='extradnsname',
|
|
28
|
+
name='last_updated',
|
|
29
|
+
field=models.DateTimeField(auto_now=True, null=True),
|
|
30
|
+
),
|
|
31
|
+
migrations.AddField(
|
|
32
|
+
model_name='extradnsname',
|
|
33
|
+
name='tags',
|
|
34
|
+
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
|
35
|
+
),
|
|
36
|
+
]
|
|
File without changes
|
|
@@ -12,7 +12,7 @@ from dns import rcode
|
|
|
12
12
|
from dns.tsig import HMAC_MD5, HMAC_SHA1, HMAC_SHA224, HMAC_SHA256, HMAC_SHA384, HMAC_SHA512
|
|
13
13
|
from netaddr import IPNetwork, ip
|
|
14
14
|
from typing import Optional
|
|
15
|
-
|
|
15
|
+
from netbox.models import NetBoxModel
|
|
16
16
|
from ipam.fields import IPNetworkField
|
|
17
17
|
from ipam.models import IPAddress
|
|
18
18
|
from .utils import normalize_fqdn
|
|
@@ -325,7 +325,7 @@ class DNSStatus(models.Model):
|
|
|
325
325
|
return format_html('<span style="color:{colour}">{output}</span', colour=colour, output=output)
|
|
326
326
|
|
|
327
327
|
|
|
328
|
-
class ExtraDNSName(
|
|
328
|
+
class ExtraDNSName(NetBoxModel):
|
|
329
329
|
ip_address = models.ForeignKey(
|
|
330
330
|
to=IPAddress,
|
|
331
331
|
verbose_name=_('IP address'),
|
|
@@ -367,7 +367,7 @@ class ExtraDNSName(models.Model):
|
|
|
367
367
|
return self.name
|
|
368
368
|
|
|
369
369
|
def get_absolute_url(self):
|
|
370
|
-
return reverse('plugins:netbox_ddns:
|
|
370
|
+
return reverse('plugins:netbox_ddns:extradnsname', args=[self.ip_address.pk, self.pk])
|
|
371
371
|
|
|
372
372
|
def clean(self):
|
|
373
373
|
# Ensure trailing dots from domain-style fields
|
|
@@ -4,10 +4,10 @@ from netbox_ddns.models import ExtraDNSName
|
|
|
4
4
|
try:
|
|
5
5
|
# NetBox >= 3.2.0
|
|
6
6
|
from netbox.tables import BaseTable
|
|
7
|
-
from netbox.tables.columns import ToggleColumn
|
|
7
|
+
from netbox.tables.columns import ToggleColumn, DateTimeColumn
|
|
8
8
|
except ImportError:
|
|
9
9
|
# NetBox < 3.2.0
|
|
10
|
-
from utilities.tables import BaseTable, ToggleColumn
|
|
10
|
+
from utilities.tables import BaseTable, ToggleColumn, DateTimeColumn
|
|
11
11
|
|
|
12
12
|
FORWARD_DNS = """
|
|
13
13
|
{% if record.forward_action is not None %}
|
|
@@ -21,13 +21,13 @@ FORWARD_DNS = """
|
|
|
21
21
|
ACTIONS = """
|
|
22
22
|
{% if perms.netbox_ddns.change_extradnsname %}
|
|
23
23
|
<a href="{% url 'plugins:netbox_ddns:extradnsname_edit' ipaddress_pk=record.ip_address.pk pk=record.pk %}"
|
|
24
|
-
class="btn btn-
|
|
24
|
+
class="btn btn-warning">
|
|
25
25
|
<i class="mdi mdi-pencil" aria-hidden="true"></i>
|
|
26
26
|
</a>
|
|
27
27
|
{% endif %}
|
|
28
28
|
{% if perms.netbox_ddns.delete_extradnsname %}
|
|
29
29
|
<a href="{% url 'plugins:netbox_ddns:extradnsname_delete' ipaddress_pk=record.ip_address.pk pk=record.pk %}"
|
|
30
|
-
class="btn btn-
|
|
30
|
+
class="btn btn-danger">
|
|
31
31
|
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i>
|
|
32
32
|
</a>
|
|
33
33
|
{% endif %}
|
|
@@ -37,7 +37,7 @@ ACTIONS = """
|
|
|
37
37
|
class PrefixTable(BaseTable):
|
|
38
38
|
pk = ToggleColumn()
|
|
39
39
|
name = tables.Column()
|
|
40
|
-
last_update =
|
|
40
|
+
last_update = DateTimeColumn()
|
|
41
41
|
forward_dns = tables.TemplateColumn(template_code=FORWARD_DNS)
|
|
42
42
|
actions = tables.TemplateColumn(
|
|
43
43
|
template_code=ACTIONS,
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
{% extends 'generic/_base.html' %}
|
|
2
|
+
{% load buttons %}
|
|
3
|
+
{% load custom_links %}
|
|
4
|
+
{% load helpers %}
|
|
5
|
+
{% load perms %}
|
|
6
|
+
{% load plugins %}
|
|
7
|
+
{% load tabs %}
|
|
8
|
+
{% load i18n %}
|
|
9
|
+
|
|
10
|
+
{% comment %}
|
|
11
|
+
Blocks:
|
|
12
|
+
- page-header: Content displayed above the primary page content
|
|
13
|
+
- breadcrumbs: Breadcrumb list items(HTML
|
|
14
|
+
<li> elements)
|
|
15
|
+
- object_identifier: Unique identifier for the object
|
|
16
|
+
- title: Page title
|
|
17
|
+
- subtitle: Additional context displayed below the title
|
|
18
|
+
- controls: Control elements displayed between the header and content
|
|
19
|
+
- control-buttons: Action buttons (add/edit/delete/etc.)
|
|
20
|
+
- extra_controls: Any additional action buttons to display
|
|
21
|
+
- tabs: Page tabs
|
|
22
|
+
- content: Primary page content
|
|
23
|
+
- modals: Any pre-loaded modals
|
|
24
|
+
|
|
25
|
+
Context:
|
|
26
|
+
- object: The object being viewed
|
|
27
|
+
{% endcomment %}
|
|
28
|
+
|
|
29
|
+
{% block page-header %}
|
|
30
|
+
<div class="container-fluid">
|
|
31
|
+
<div class="d-flex justify-content-between align-items-center mt-2">
|
|
32
|
+
|
|
33
|
+
{# Object identifier #}
|
|
34
|
+
<code class="d-block text-muted bg-transparent px-0">
|
|
35
|
+
{% block object_identifier %}
|
|
36
|
+
{{ object|meta:"app_label" }}.{{ object|meta:"model_name" }}:{{ object.pk }}
|
|
37
|
+
{% if object.slug %}({{ object.slug }}){% endif %}
|
|
38
|
+
{% endblock object_identifier %}
|
|
39
|
+
</code>
|
|
40
|
+
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
{{ block.super }}
|
|
44
|
+
{% endblock page-header %}
|
|
45
|
+
|
|
46
|
+
{% block title %}{{ object }}{% endblock %}
|
|
47
|
+
|
|
48
|
+
{% block subtitle %}
|
|
49
|
+
<div class="text-secondary fs-5">
|
|
50
|
+
{% trans "Created" %} {{ object.created|isodatetime:"minutes" }}
|
|
51
|
+
{% if object.last_updated %}
|
|
52
|
+
<span class="separator">·</span>
|
|
53
|
+
{% trans "Updated" %} {{ object.last_updated|isodatetime:"minutes" }}
|
|
54
|
+
{% endif %}
|
|
55
|
+
</div>
|
|
56
|
+
{% endblock subtitle %}
|
|
57
|
+
|
|
58
|
+
{% block controls %}
|
|
59
|
+
<div class="btn-list justify-content-end mb-2">
|
|
60
|
+
{% plugin_buttons object %}
|
|
61
|
+
|
|
62
|
+
{# Add/edit/delete/etc. buttons #}
|
|
63
|
+
{% block control-buttons %}
|
|
64
|
+
|
|
65
|
+
{# Extra buttons #}
|
|
66
|
+
{% block extra_controls %}{% endblock %}
|
|
67
|
+
|
|
68
|
+
{# Default buttons #}
|
|
69
|
+
{% if perms.extras.add_bookmark and object.bookmarks %}
|
|
70
|
+
{% bookmark_button object %}
|
|
71
|
+
{% endif %}
|
|
72
|
+
{% if perms.extras.add_subscription and object.subscriptions %}
|
|
73
|
+
{% subscribe_button object %}
|
|
74
|
+
{% endif %}
|
|
75
|
+
{% if request.user|can_change:object %}
|
|
76
|
+
{% load i18n %}
|
|
77
|
+
<a href="{% url 'plugins:netbox_ddns:extradnsname_edit' ipaddress_pk=object.ip_address.pk pk=object.pk %}"
|
|
78
|
+
class="btn btn-yellow" role="button">
|
|
79
|
+
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
|
80
|
+
</a>
|
|
81
|
+
{% endif %}
|
|
82
|
+
{% if request.user|can_delete:object %}
|
|
83
|
+
{% load i18n %}
|
|
84
|
+
<a href="#"
|
|
85
|
+
hx-get="{% url 'plugins:netbox_ddns:extradnsname_delete' ipaddress_pk=object.ip_address.pk pk=object.pk %}"
|
|
86
|
+
hx-target="#htmx-modal-content"
|
|
87
|
+
hx-swap="innerHTML"
|
|
88
|
+
hx-select="form"
|
|
89
|
+
class="btn btn-red"
|
|
90
|
+
data-bs-toggle="modal"
|
|
91
|
+
data-bs-target="#htmx-modal"
|
|
92
|
+
>
|
|
93
|
+
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
|
94
|
+
</a>
|
|
95
|
+
|
|
96
|
+
{% endif %}
|
|
97
|
+
{% endblock control-buttons %}
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
{# Custom links #}
|
|
101
|
+
<div class="d-flex justify-content-end">
|
|
102
|
+
<div class="btn-list">
|
|
103
|
+
{% block custom-links %}
|
|
104
|
+
{% custom_links object %}
|
|
105
|
+
{% endblock custom-links %}
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
{% endblock controls %}
|
|
109
|
+
|
|
110
|
+
{% block tabs %}
|
|
111
|
+
<ul class="nav nav-tabs" role="presentation">
|
|
112
|
+
{# Primary tab #}
|
|
113
|
+
<li class="nav-item">
|
|
114
|
+
<a class="nav-link{% if not tab %} active{% endif %}" href="{{ object.get_absolute_url }}">
|
|
115
|
+
{{ object|meta:"verbose_name"|bettertitle }}</a>
|
|
116
|
+
</li>
|
|
117
|
+
|
|
118
|
+
{# Include tabs for registered model views #}
|
|
119
|
+
{% model_view_tabs object %}
|
|
120
|
+
</ul>
|
|
121
|
+
{% endblock tabs %}
|
|
122
|
+
|
|
123
|
+
{% block alerts %}
|
|
124
|
+
{% plugin_alerts object %}
|
|
125
|
+
{% endblock alerts %}
|
|
126
|
+
|
|
127
|
+
{% block content %}
|
|
128
|
+
<div class="row mb-3">
|
|
129
|
+
<div class="col col-md-6">
|
|
130
|
+
<div class="card">
|
|
131
|
+
<h5 class="card-header">Access List</h5>
|
|
132
|
+
<div class="card-body">
|
|
133
|
+
<table class="table table-hover attr-table">
|
|
134
|
+
<tr>
|
|
135
|
+
<th scope="row">Name</th>
|
|
136
|
+
<td>{{ object.name }}</td>
|
|
137
|
+
</tr>
|
|
138
|
+
<tr>
|
|
139
|
+
<th scope="row">IP Address</th>
|
|
140
|
+
<td>
|
|
141
|
+
<a href="{{ object.ip_address.get_absolute_url }}">{{ object.ip_address }}</a>
|
|
142
|
+
</td>
|
|
143
|
+
</tr>
|
|
144
|
+
<tr>
|
|
145
|
+
<th scope="row">Last update</th>
|
|
146
|
+
<td>{{ object.last_update|isodatetime }}</td>
|
|
147
|
+
</tr>
|
|
148
|
+
<tr>
|
|
149
|
+
<th scope="row">Forward DNS</th>
|
|
150
|
+
<td>
|
|
151
|
+
{% if object.forward_action is not None %}
|
|
152
|
+
{{ object.get_forward_action_display }}:
|
|
153
|
+
{{ object.get_forward_rcode_html_display }} {% else %}
|
|
154
|
+
<span class="text-muted">Not created</span>
|
|
155
|
+
{% endif %}
|
|
156
|
+
</td>
|
|
157
|
+
</tr>
|
|
158
|
+
</table>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
{% include 'inc/panels/custom_fields.html' %}
|
|
162
|
+
</div>
|
|
163
|
+
<div class="col col-md-6">{% include 'inc/panels/tags.html' %}</div>
|
|
164
|
+
</div>
|
|
165
|
+
{% endblock content %}
|
|
166
|
+
|
|
167
|
+
{% block modals %}
|
|
168
|
+
{% include 'inc/htmx_modal.html' %}
|
|
169
|
+
{% endblock modals %}
|
{netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/templates/netbox_ddns/ipaddress/dns_extra.html
RENAMED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
{% if perms.netbox_ddns.add_extradnsname %}
|
|
12
12
|
<div class="card-footer text-right noprint">
|
|
13
13
|
<a href="{% url 'plugins:netbox_ddns:extradnsname_create' ipaddress_pk=object.pk %}"
|
|
14
|
-
class="btn btn-
|
|
14
|
+
class="btn btn-primary">
|
|
15
15
|
<span class="mdi mdi-plus" aria-hidden="true"></span>Add extra DNS name
|
|
16
16
|
</a>
|
|
17
17
|
</div>
|
{netbox-ddns-1.2.9 → netbox_ddns-1.4.0}/netbox_ddns/templates/netbox_ddns/ipaddress/dns_info.html
RENAMED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
{% load helpers %}
|
|
2
|
+
|
|
1
3
|
{% if object.dnsstatus %}
|
|
2
4
|
<div class="card">
|
|
3
5
|
<h5 class="card-header"> Dynamic DNS Status </strong>
|
|
@@ -7,7 +9,7 @@
|
|
|
7
9
|
<tr>
|
|
8
10
|
<th scope="row">Last update</th>
|
|
9
11
|
<td>
|
|
10
|
-
{{ object.dnsstatus.last_update }}
|
|
12
|
+
{{ object.dnsstatus.last_update|isodatetime }}
|
|
11
13
|
</td>
|
|
12
14
|
</tr>
|
|
13
15
|
<tr>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<button type="submit" name="_edit"
|
|
6
6
|
formaction="{% url 'plugins:netbox_ddns:ipaddress_dnsname_recreate' ipaddress_pk=object.pk %}"
|
|
7
|
-
class="btn btn-
|
|
7
|
+
class="btn btn-secondary">
|
|
8
8
|
<span class="mdi mdi-refresh" aria-hidden="true"></span> Recreate DNS
|
|
9
9
|
</button>
|
|
10
10
|
</form>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from django.urls import path
|
|
2
2
|
|
|
3
|
-
from .views import ExtraDNSNameCreateView, ExtraDNSNameDeleteView, ExtraDNSNameEditView, IPAddressDNSNameRecreateView
|
|
3
|
+
from .views import ExtraDNSNameCreateView, ExtraDNSNameDeleteView, ExtraDNSNameEditView, IPAddressDNSNameRecreateView, ExtraDNSNameView
|
|
4
4
|
|
|
5
5
|
urlpatterns = [
|
|
6
6
|
path(route='ip-addresses/<int:ipaddress_pk>/recreate/',
|
|
@@ -15,4 +15,8 @@ urlpatterns = [
|
|
|
15
15
|
path(route='ip-addresses/<int:ipaddress_pk>/extra/<int:pk>/delete/',
|
|
16
16
|
view=ExtraDNSNameDeleteView.as_view(),
|
|
17
17
|
name='extradnsname_delete'),
|
|
18
|
+
|
|
19
|
+
path(route='ip-addresses/<int:ipaddress_pk>/extra/<int:pk>/',
|
|
20
|
+
view=ExtraDNSNameView.as_view(),
|
|
21
|
+
name='extradnsname'),
|
|
18
22
|
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from django.contrib import messages
|
|
2
2
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
|
3
3
|
from django.http import Http404
|
|
4
|
-
from django.shortcuts import get_object_or_404, redirect
|
|
4
|
+
from django.shortcuts import get_object_or_404, redirect, render
|
|
5
5
|
from django.urls import reverse
|
|
6
6
|
from django.utils.translation import gettext as _
|
|
7
7
|
from django.views import View
|
|
@@ -12,12 +12,16 @@ from netbox_ddns.forms import ExtraDNSNameEditForm
|
|
|
12
12
|
from netbox_ddns.models import DNSStatus, ExtraDNSName
|
|
13
13
|
from netbox_ddns.utils import normalize_fqdn
|
|
14
14
|
|
|
15
|
+
from utilities.forms import ConfirmationForm
|
|
16
|
+
from utilities.htmx import htmx_partial
|
|
17
|
+
from utilities.views import get_viewname
|
|
18
|
+
|
|
15
19
|
try:
|
|
16
20
|
# NetBox <= 2.9
|
|
17
21
|
from utilities.views import ObjectDeleteView, ObjectEditView
|
|
18
22
|
except ImportError:
|
|
19
23
|
# NetBox >= 2.10
|
|
20
|
-
from netbox.views.generic import ObjectDeleteView, ObjectEditView
|
|
24
|
+
from netbox.views.generic import ObjectDeleteView, ObjectEditView, ObjectView
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
# noinspection PyMethodMayBeStatic
|
|
@@ -63,6 +67,11 @@ class ExtraDNSNameCreateView(PermissionRequiredMixin, ExtraDNSNameObjectMixin, O
|
|
|
63
67
|
def model_form(self):
|
|
64
68
|
return self.form
|
|
65
69
|
|
|
70
|
+
|
|
71
|
+
class ExtraDNSNameView(PermissionRequiredMixin,ExtraDNSNameObjectMixin,ObjectView):
|
|
72
|
+
permission_required = 'netbox_ddns.view_extradnsname'
|
|
73
|
+
queryset = ExtraDNSName.objects.all()
|
|
74
|
+
|
|
66
75
|
class ExtraDNSNameEditView(ExtraDNSNameCreateView):
|
|
67
76
|
permission_required = 'netbox_ddns.change_extradnsname'
|
|
68
77
|
|
|
@@ -71,6 +80,38 @@ class ExtraDNSNameDeleteView(PermissionRequiredMixin, ExtraDNSNameObjectMixin, O
|
|
|
71
80
|
permission_required = 'netbox_ddns.delete_extradnsname'
|
|
72
81
|
queryset = ExtraDNSName.objects.all()
|
|
73
82
|
|
|
83
|
+
# Override request handler to fix the error on delete GET due to missing reverse route argument
|
|
84
|
+
def get(self, request, *args, **kwargs):
|
|
85
|
+
"""
|
|
86
|
+
GET request handler.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
request: The current request
|
|
90
|
+
"""
|
|
91
|
+
obj = self.get_object(**kwargs)
|
|
92
|
+
form = ConfirmationForm(initial=request.GET)
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
dependent_objects = self._get_dependent_objects(obj)
|
|
96
|
+
except ProtectedError as e:
|
|
97
|
+
return self._handle_protected_objects(obj, e.protected_objects, request, e)
|
|
98
|
+
except RestrictedError as e:
|
|
99
|
+
return self._handle_protected_objects(obj, e.restricted_objects, request, e)
|
|
100
|
+
|
|
101
|
+
# If this is an HTMX request, return only the rendered deletion form as modal content
|
|
102
|
+
if htmx_partial(request):
|
|
103
|
+
viewname = get_viewname(self.queryset.model, action='delete')
|
|
104
|
+
form_url = reverse(viewname, kwargs={'pk': obj.pk, 'ipaddress_pk': obj.ip_address.pk})
|
|
105
|
+
return render(request, 'htmx/delete_form.html', {
|
|
106
|
+
'object': obj,
|
|
107
|
+
'object_type': self.queryset.model._meta.verbose_name,
|
|
108
|
+
'form': form,
|
|
109
|
+
'form_url': form_url,
|
|
110
|
+
'dependent_objects': dependent_objects,
|
|
111
|
+
**self.get_extra_context(request, obj),
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
|
|
74
115
|
|
|
75
116
|
class IPAddressDNSNameRecreateView(PermissionRequiredMixin, View):
|
|
76
117
|
permission_required = 'ipam.change_ipaddress'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: netbox-ddns
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Dynamic DNS Connector for NetBox
|
|
5
5
|
Home-page: https://github.com/sjm-steffann/netbox-ddns
|
|
6
6
|
Author: Sander Steffann
|
|
@@ -12,7 +12,7 @@ Classifier: Framework :: Django :: 3.0
|
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.6
|
|
15
|
-
Requires-Python: >=3.
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE.txt
|
|
18
18
|
Requires-Dist: setuptools
|
|
@@ -33,6 +33,12 @@ For now all configuration is done in the NetBox admin back-end. A later version
|
|
|
33
33
|
|
|
34
34
|
This plugin in compatible with [NetBox](https://netbox.readthedocs.org/) v3.0.0 and greater, support for Netbox v2.11.0 is dropped in v1.1.4 due to UI implementation.
|
|
35
35
|
|
|
36
|
+
> [!Important]
|
|
37
|
+
> Netbox 4.0 - Admin interface disabled by default<br />
|
|
38
|
+
> Can be re-enabled by specifying `DJANGO_ADMIN_ENABLED = True` in `configuration.py`<br />
|
|
39
|
+
> If static files are not loaded, re-run `upgrade.sh` this will copy back the required static assets.
|
|
40
|
+
|
|
41
|
+
|
|
36
42
|
## Installation
|
|
37
43
|
|
|
38
44
|
First, add `netbox-ddns` to your `/opt/netbox/local_requirements.txt` file. Create it if it doesn't exist.
|
|
@@ -7,8 +7,10 @@ setup.py
|
|
|
7
7
|
netbox_ddns/__init__.py
|
|
8
8
|
netbox_ddns/admin.py
|
|
9
9
|
netbox_ddns/background_tasks.py
|
|
10
|
+
netbox_ddns/filtersets.py
|
|
10
11
|
netbox_ddns/forms.py
|
|
11
12
|
netbox_ddns/models.py
|
|
13
|
+
netbox_ddns/search.py
|
|
12
14
|
netbox_ddns/signals.py
|
|
13
15
|
netbox_ddns/tables.py
|
|
14
16
|
netbox_ddns/template_content.py
|
|
@@ -22,6 +24,10 @@ netbox_ddns.egg-info/dependency_links.txt
|
|
|
22
24
|
netbox_ddns.egg-info/not-zip-safe
|
|
23
25
|
netbox_ddns.egg-info/requires.txt
|
|
24
26
|
netbox_ddns.egg-info/top_level.txt
|
|
27
|
+
netbox_ddns/api/__init__.py
|
|
28
|
+
netbox_ddns/api/serializers.py
|
|
29
|
+
netbox_ddns/api/urls.py
|
|
30
|
+
netbox_ddns/api/views.py
|
|
25
31
|
netbox_ddns/migrations/0001_initial.py
|
|
26
32
|
netbox_ddns/migrations/0002_add_ttl.py
|
|
27
33
|
netbox_ddns/migrations/0003_dnsstatus.py
|
|
@@ -30,7 +36,10 @@ netbox_ddns/migrations/0005_extradnsname.py
|
|
|
30
36
|
netbox_ddns/migrations/0006_extradns_cname.py
|
|
31
37
|
netbox_ddns/migrations/0007_zone_meta.py
|
|
32
38
|
netbox_ddns/migrations/0008_server_server_port.py
|
|
39
|
+
netbox_ddns/migrations/0009_alter_dnsstatus_id_alter_extradnsname_id_and_more.py
|
|
40
|
+
netbox_ddns/migrations/0010_extradnsname_created_extradnsname_custom_field_data_and_more.py
|
|
33
41
|
netbox_ddns/migrations/__init__.py
|
|
42
|
+
netbox_ddns/templates/netbox_ddns/extradnsname.html
|
|
34
43
|
netbox_ddns/templates/netbox_ddns/ipaddress/dns_extra.html
|
|
35
44
|
netbox_ddns/templates/netbox_ddns/ipaddress/dns_info.html
|
|
36
45
|
netbox_ddns/templates/netbox_ddns/ipaddress/dns_refresh_button.html
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|