mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-23 07:56:44 -06:00
WIP
This commit is contained in:
parent
60fc28e37d
commit
4880111622
@ -9,7 +9,7 @@ from django.contrib.auth import get_user_model
|
|||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
APPS = ('circuits', 'core', 'dcim', 'extras', 'ipam', 'tenancy', 'users', 'virtualization', 'wireless')
|
APPS = ('circuits', 'core', 'dcim', 'extras', 'ipam', 'tenancy', 'users', 'virtualization', 'vpn', 'wireless')
|
||||||
|
|
||||||
BANNER_TEXT = """### NetBox interactive shell ({node})
|
BANNER_TEXT = """### NetBox interactive shell ({node})
|
||||||
### Python {python} | Django {django} | NetBox {netbox}
|
### Python {python} | Django {django} | NetBox {netbox}
|
||||||
|
@ -39,6 +39,7 @@ class APIRootView(APIView):
|
|||||||
'tenancy': reverse('tenancy-api:api-root', request=request, format=format),
|
'tenancy': reverse('tenancy-api:api-root', request=request, format=format),
|
||||||
'users': reverse('users-api:api-root', request=request, format=format),
|
'users': reverse('users-api:api-root', request=request, format=format),
|
||||||
'virtualization': reverse('virtualization-api:api-root', request=request, format=format),
|
'virtualization': reverse('virtualization-api:api-root', request=request, format=format),
|
||||||
|
'vpn': reverse('vpn-api:api-root', request=request, format=format),
|
||||||
'wireless': reverse('wireless-api:api-root', request=request, format=format),
|
'wireless': reverse('wireless-api:api-root', request=request, format=format),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
92
netbox/templates/vpn/ipsecprofile.html
Normal file
92
netbox/templates/vpn/ipsecprofile.html
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
{% extends 'generic/object.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
{% load plugins %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">{% trans "IPSec Profile" %}</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Name" %}</th>
|
||||||
|
<td>{{ object.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Protocol" %}</th>
|
||||||
|
<td>{{ object.get_protocol_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "IKE Version" %}</th>
|
||||||
|
<td>{{ object.get_ike_version_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Description" %}</th>
|
||||||
|
<td>{{ object.description|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'inc/panels/custom_fields.html' %}
|
||||||
|
{% include 'inc/panels/tags.html' %}
|
||||||
|
{% include 'inc/panels/comments.html' %}
|
||||||
|
{% plugin_left_page object %}
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">{% trans "Phase 1 Parameters" %}</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Encryption" %}</th>
|
||||||
|
<td>{{ object.get_phase1_encryption_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Authentication" %}</th>
|
||||||
|
<td>{{ object.get_phase1_authentication_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "DH Group" %}</th>
|
||||||
|
<td>{{ object.get_phase1_group_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "SA Lifetime" %}</th>
|
||||||
|
<td>{{ object.phase1_sa_lifetime|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">{% trans "Phase 2 Parameters" %}</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Encryption" %}</th>
|
||||||
|
<td>{{ object.get_phase2_encryption_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Authentication" %}</th>
|
||||||
|
<td>{{ object.get_phase2_authentication_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "DH Group" %}</th>
|
||||||
|
<td>{{ object.get_phase2_group_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "SA Lifetime" %}</th>
|
||||||
|
<td>{{ object.phase2_sa_lifetime|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% plugin_right_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
{% plugin_full_width_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
81
netbox/templates/vpn/tunnel.html
Normal file
81
netbox/templates/vpn/tunnel.html
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
{% extends 'generic/object.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
{% load plugins %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">{% trans "Tunnel" %}</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Name" %}</th>
|
||||||
|
<td>{{ object.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Status" %}</th>
|
||||||
|
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Encapsulation" %}</th>
|
||||||
|
<td>{{ object.get_encapsulation_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "IPSec profile" %}</th>
|
||||||
|
<td>{{ object.ipsec_profile|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Tenant" %}</th>
|
||||||
|
<td>
|
||||||
|
{% if object.tenant.group %}
|
||||||
|
{{ object.tenant.group|linkify }} /
|
||||||
|
{% endif %}
|
||||||
|
{{ object.tenant|linkify|placeholder }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Pre-shared key" %}</th>
|
||||||
|
<td>{{ object.preshared_key|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Tunnel ID" %}</th>
|
||||||
|
<td>{{ object.tunnel_id|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Description" %}</th>
|
||||||
|
<td>{{ object.description|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% plugin_left_page object %}
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-6">
|
||||||
|
{% include 'inc/panels/custom_fields.html' %}
|
||||||
|
{% include 'inc/panels/tags.html' %}
|
||||||
|
{% include 'inc/panels/comments.html' %}
|
||||||
|
{% plugin_right_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">{% trans "Terminations" %}</h5>
|
||||||
|
<div class="card-body htmx-container table-responsive"
|
||||||
|
hx-get="{% url 'vpn:tunneltermination_list' %}?tunnel_id={{ object.pk }}"
|
||||||
|
hx-trigger="load"
|
||||||
|
></div>
|
||||||
|
{% if perms.vpn.add_tunneltermination %}
|
||||||
|
<div class="card-footer text-end noprint">
|
||||||
|
<a href="{% url 'vpn:tunneltermination_add' %}?tunnel={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
|
||||||
|
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add a Termination" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% plugin_full_width_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -69,14 +69,14 @@ class TunnelTerminationSerializer(NetBoxModelSerializer):
|
|||||||
model = TunnelTermination
|
model = TunnelTermination
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'url', 'display', 'tunnel', 'role', 'interface_type', 'interface_id', 'interface', 'outside_ip',
|
'id', 'url', 'display', 'tunnel', 'role', 'interface_type', 'interface_id', 'interface', 'outside_ip',
|
||||||
'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
|
'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
|
|
||||||
@extend_schema_field(serializers.JSONField(allow_null=True))
|
@extend_schema_field(serializers.JSONField(allow_null=True))
|
||||||
def get_interface(self, obj):
|
def get_interface(self, obj):
|
||||||
serializer = get_serializer_for_model(obj.interface, prefix=NESTED_SERIALIZER_PREFIX)
|
serializer = get_serializer_for_model(obj.interface, prefix=NESTED_SERIALIZER_PREFIX)
|
||||||
context = {'request': self.context['request']}
|
context = {'request': self.context['request']}
|
||||||
return serializer(obj.assigned_object, context=context).data
|
return serializer(obj.interface, context=context).data
|
||||||
|
|
||||||
|
|
||||||
class IPSecProfileSerializer(NetBoxModelSerializer):
|
class IPSecProfileSerializer(NetBoxModelSerializer):
|
||||||
|
@ -35,7 +35,7 @@ class TunnelViewSet(NetBoxModelViewSet):
|
|||||||
|
|
||||||
|
|
||||||
class TunnelTerminationViewSet(NetBoxModelViewSet):
|
class TunnelTerminationViewSet(NetBoxModelViewSet):
|
||||||
queryset = Tunnel.objects.prefetch_related('tunnel')
|
queryset = TunnelTermination.objects.prefetch_related('tunnel')
|
||||||
serializer_class = serializers.TunnelTerminationSerializer
|
serializer_class = serializers.TunnelTerminationSerializer
|
||||||
filterset_class = filtersets.TunnelTerminationFilterSet
|
filterset_class = filtersets.TunnelTerminationFilterSet
|
||||||
|
|
||||||
|
@ -24,12 +24,14 @@ class TunnelStatusChoices(ChoiceSet):
|
|||||||
class TunnelEncapsulationChoices(ChoiceSet):
|
class TunnelEncapsulationChoices(ChoiceSet):
|
||||||
ENCAP_GRE = 'gre'
|
ENCAP_GRE = 'gre'
|
||||||
ENCAP_IP_IP = 'ip-ip'
|
ENCAP_IP_IP = 'ip-ip'
|
||||||
ENCAP_IPSEC = 'ipsec'
|
ENCAP_IPSEC_TRANSPORT = 'ipsec-transport'
|
||||||
|
ENCAP_IPSEC_TUNNEL = 'ipsec-tunnel'
|
||||||
|
|
||||||
CHOICES = [
|
CHOICES = [
|
||||||
(ENCAP_IPSEC, _('IPsec')),
|
(ENCAP_IPSEC_TRANSPORT, _('IPsec - Transport')),
|
||||||
(ENCAP_IP_IP, _('Active')),
|
(ENCAP_IPSEC_TUNNEL, _('IPsec - Tunnel')),
|
||||||
(ENCAP_GRE, _('Disabled')),
|
(ENCAP_IP_IP, _('IP-in-IP')),
|
||||||
|
(ENCAP_GRE, _('GRE')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -39,9 +41,9 @@ class TunnelTerminationRoleChoices(ChoiceSet):
|
|||||||
ROLE_SPOKE = 'spoke'
|
ROLE_SPOKE = 'spoke'
|
||||||
|
|
||||||
CHOICES = [
|
CHOICES = [
|
||||||
(ROLE_PEER, _('Peer')),
|
(ROLE_PEER, _('Peer'), 'green'),
|
||||||
(ROLE_HUB, _('Hub')),
|
(ROLE_HUB, _('Hub'), 'blue'),
|
||||||
(ROLE_SPOKE, _('Spoke')),
|
(ROLE_SPOKE, _('Spoke'), 'orange'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ from django import forms
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from netbox.forms import NetBoxModelFilterSetForm
|
from netbox.forms import NetBoxModelFilterSetForm
|
||||||
|
from tenancy.forms import TenancyFilterForm
|
||||||
from utilities.forms.fields import DynamicModelMultipleChoiceField, TagFilterField
|
from utilities.forms.fields import DynamicModelMultipleChoiceField, TagFilterField
|
||||||
from vpn.choices import *
|
from vpn.choices import *
|
||||||
from vpn.models import *
|
from vpn.models import *
|
||||||
@ -13,13 +14,13 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TunnelFilterForm(NetBoxModelFilterSetForm):
|
class TunnelFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Tunnel
|
model = Tunnel
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'filter_id', 'tag')),
|
(None, ('q', 'filter_id', 'tag')),
|
||||||
(_('Tunnel'), ('status', 'encapsulation', 'tunnel_id')),
|
(_('Tunnel'), ('status', 'encapsulation', 'tunnel_id')),
|
||||||
(_('Security'), ('ipsec_profile_id', 'preshared_key')),
|
(_('Security'), ('ipsec_profile_id', 'preshared_key')),
|
||||||
(_('Tenancy'), ('tenant',)),
|
(_('Tenancy'), ('tenant_group_id', 'tenant_id')),
|
||||||
)
|
)
|
||||||
status = forms.MultipleChoiceField(
|
status = forms.MultipleChoiceField(
|
||||||
label=_('Status'),
|
label=_('Status'),
|
||||||
@ -36,6 +37,14 @@ class TunnelFilterForm(NetBoxModelFilterSetForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=_('IPSec profile')
|
label=_('IPSec profile')
|
||||||
)
|
)
|
||||||
|
preshared_key = forms.CharField(
|
||||||
|
required=False,
|
||||||
|
label=_('Pre-shared key')
|
||||||
|
)
|
||||||
|
tunnel_id = forms.IntegerField(
|
||||||
|
required=False,
|
||||||
|
label=_('Tunnel ID')
|
||||||
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ from django import forms
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from dcim.models import Interface
|
from dcim.models import Interface
|
||||||
|
from ipam.models import IPAddress
|
||||||
from netbox.forms import NetBoxModelForm
|
from netbox.forms import NetBoxModelForm
|
||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
from utilities.forms.fields import CommentField, DynamicModelChoiceField
|
from utilities.forms.fields import CommentField, DynamicModelChoiceField
|
||||||
@ -17,7 +18,8 @@ __all__ = (
|
|||||||
|
|
||||||
class TunnelForm(TenancyForm, NetBoxModelForm):
|
class TunnelForm(TenancyForm, NetBoxModelForm):
|
||||||
ipsec_profile = DynamicModelChoiceField(
|
ipsec_profile = DynamicModelChoiceField(
|
||||||
queryset=IPSecProfile.objects.all()
|
queryset=IPSecProfile.objects.all(),
|
||||||
|
label=_('IPSec Profile')
|
||||||
)
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
@ -51,6 +53,11 @@ class TunnelTerminationForm(NetBoxModelForm):
|
|||||||
selector=True,
|
selector=True,
|
||||||
label=_('Interface'),
|
label=_('Interface'),
|
||||||
)
|
)
|
||||||
|
outside_ip = DynamicModelChoiceField(
|
||||||
|
queryset=IPAddress.objects.all(),
|
||||||
|
selector=True,
|
||||||
|
label=_('Outside IP'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TunnelTermination
|
model = TunnelTermination
|
||||||
|
0
netbox/vpn/graphql/__init__.py
Normal file
0
netbox/vpn/graphql/__init__.py
Normal file
26
netbox/vpn/graphql/schema.py
Normal file
26
netbox/vpn/graphql/schema.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import graphene
|
||||||
|
|
||||||
|
from netbox.graphql.fields import ObjectField, ObjectListField
|
||||||
|
from utilities.graphql_optimizer import gql_query_optimizer
|
||||||
|
from vpn import models
|
||||||
|
from .types import *
|
||||||
|
|
||||||
|
|
||||||
|
class VPNQuery(graphene.ObjectType):
|
||||||
|
ipsec_profile = ObjectField(IPSecProfileType)
|
||||||
|
ipsec_profile_list = ObjectListField(IPSecProfileType)
|
||||||
|
|
||||||
|
def resolve_ipsec_profile_list(root, info, **kwargs):
|
||||||
|
return gql_query_optimizer(models.IPSecProfile.objects.all(), info)
|
||||||
|
|
||||||
|
tunnel = ObjectField(TunnelType)
|
||||||
|
tunnel_list = ObjectListField(TunnelType)
|
||||||
|
|
||||||
|
def resolve_tunnel_list(root, info, **kwargs):
|
||||||
|
return gql_query_optimizer(models.Tunnel.objects.all(), info)
|
||||||
|
|
||||||
|
tunnel_termination = ObjectField(TunnelTerminationType)
|
||||||
|
tunnel_termination_list = ObjectListField(TunnelTerminationType)
|
||||||
|
|
||||||
|
def resolve_tunnel_termination_list(root, info, **kwargs):
|
||||||
|
return gql_query_optimizer(models.TunnelTermination.objects.all(), info)
|
33
netbox/vpn/graphql/types.py
Normal file
33
netbox/vpn/graphql/types.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
|
||||||
|
from netbox.graphql.types import ObjectType, OrganizationalObjectType, NetBoxObjectType
|
||||||
|
from vpn import filtersets, models
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'IPSecProfileType',
|
||||||
|
'TunnelTerminationType',
|
||||||
|
'TunnelType',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelTerminationType(CustomFieldsMixin, TagsMixin, ObjectType):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.TunnelTermination
|
||||||
|
fields = '__all__'
|
||||||
|
filterset_class = filtersets.TunnelTerminationFilterSet
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelType(NetBoxObjectType):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Tunnel
|
||||||
|
fields = '__all__'
|
||||||
|
filterset_class = filtersets.TunnelFilterSet
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecProfileType(OrganizationalObjectType):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.IPSecProfile
|
||||||
|
fields = '__all__'
|
||||||
|
filterset_class = filtersets.IPSecProfileFilterSet
|
93
netbox/vpn/migrations/0001_initial.py
Normal file
93
netbox/vpn/migrations/0001_initial.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-11-07 21:49
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import taggit.managers
|
||||||
|
import utilities.json
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tenancy', '0011_contactassignment_tags'),
|
||||||
|
('extras', '0099_cachedvalue_ordering'),
|
||||||
|
('contenttypes', '0002_remove_content_type_name'),
|
||||||
|
('ipam', '0067_ipaddress_index_host'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='IPSecProfile',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||||
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||||
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
|
('comments', models.TextField(blank=True)),
|
||||||
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
|
('protocol', models.CharField()),
|
||||||
|
('ike_version', models.PositiveSmallIntegerField(default=2)),
|
||||||
|
('phase1_encryption', models.CharField()),
|
||||||
|
('phase1_authentication', models.CharField()),
|
||||||
|
('phase1_group', models.PositiveSmallIntegerField()),
|
||||||
|
('phase1_sa_lifetime', models.PositiveSmallIntegerField(blank=True, null=True)),
|
||||||
|
('phase2_encryption', models.CharField()),
|
||||||
|
('phase2_authentication', models.CharField()),
|
||||||
|
('phase2_group', models.PositiveSmallIntegerField()),
|
||||||
|
('phase2_sa_lifetime', models.PositiveSmallIntegerField(blank=True, null=True)),
|
||||||
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'tunnel',
|
||||||
|
'verbose_name_plural': 'tunnels',
|
||||||
|
'ordering': ('name',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tunnel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||||
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||||
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
|
('comments', models.TextField(blank=True)),
|
||||||
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
|
('status', models.CharField(default='active', max_length=50)),
|
||||||
|
('encapsulation', models.CharField(max_length=50)),
|
||||||
|
('preshared_key', models.TextField(blank=True)),
|
||||||
|
('tunnel_id', models.PositiveBigIntegerField(blank=True)),
|
||||||
|
('ipsec_profile', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tunnels', to='vpn.ipsecprofile')),
|
||||||
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
|
('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='tunnels', to='tenancy.tenant')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'tunnel',
|
||||||
|
'verbose_name_plural': 'tunnels',
|
||||||
|
'ordering': ('name',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TunnelTermination',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||||
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||||
|
('role', models.CharField(default='peer', max_length=50)),
|
||||||
|
('interface_id', models.PositiveBigIntegerField(blank=True, null=True)),
|
||||||
|
('interface_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')),
|
||||||
|
('outside_ip', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='tunnel_termination', to='ipam.ipaddress')),
|
||||||
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
|
('tunnel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='vpn.tunnel')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'tunnel termination',
|
||||||
|
'verbose_name_plural': 'tunnel terminations',
|
||||||
|
'ordering': ('tunnel', 'pk'),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-11-08 16:04
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('vpn', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ipsecprofile',
|
||||||
|
name='phase1_sa_lifetime',
|
||||||
|
field=models.PositiveIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ipsecprofile',
|
||||||
|
name='phase2_sa_lifetime',
|
||||||
|
field=models.PositiveIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
18
netbox/vpn/migrations/0003_alter_tunnel_tunnel_id.py
Normal file
18
netbox/vpn/migrations/0003_alter_tunnel_tunnel_id.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-11-08 16:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('vpn', '0002_alter_ipsecprofile_phase1_sa_lifetime_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='tunnel',
|
||||||
|
name='tunnel_id',
|
||||||
|
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -40,7 +40,7 @@ class IPSecProfile(PrimaryModel):
|
|||||||
choices=DHGroupChoices,
|
choices=DHGroupChoices,
|
||||||
help_text=_('Diffie-Hellman group')
|
help_text=_('Diffie-Hellman group')
|
||||||
)
|
)
|
||||||
phase1_sa_lifetime = models.PositiveSmallIntegerField(
|
phase1_sa_lifetime = models.PositiveIntegerField(
|
||||||
verbose_name=_('phase 1 SA lifetime'),
|
verbose_name=_('phase 1 SA lifetime'),
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
@ -61,7 +61,7 @@ class IPSecProfile(PrimaryModel):
|
|||||||
choices=DHGroupChoices,
|
choices=DHGroupChoices,
|
||||||
help_text=_('Diffie-Hellman group')
|
help_text=_('Diffie-Hellman group')
|
||||||
)
|
)
|
||||||
phase2_sa_lifetime = models.PositiveSmallIntegerField(
|
phase2_sa_lifetime = models.PositiveIntegerField(
|
||||||
verbose_name=_('phase 2 SA lifetime'),
|
verbose_name=_('phase 2 SA lifetime'),
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
@ -70,8 +70,8 @@ class IPSecProfile(PrimaryModel):
|
|||||||
# TODO: Add PFS group?
|
# TODO: Add PFS group?
|
||||||
|
|
||||||
clone_fields = (
|
clone_fields = (
|
||||||
'protocol', 'ike_version', 'phase1_encryption', 'phase1_authentication', 'phase1_group', 'phase1_as_lifetime',
|
'protocol', 'ike_version', 'phase1_encryption', 'phase1_authentication', 'phase1_group', 'phase1_sa_lifetime',
|
||||||
'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_as_lifetime',
|
'phase2_encryption', 'phase2_authentication', 'phase2_group', 'phase2_sa_lifetime',
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -50,7 +50,8 @@ class Tunnel(PrimaryModel):
|
|||||||
)
|
)
|
||||||
tunnel_id = models.PositiveBigIntegerField(
|
tunnel_id = models.PositiveBigIntegerField(
|
||||||
verbose_name=_('tunnel ID'),
|
verbose_name=_('tunnel ID'),
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
clone_fields = (
|
clone_fields = (
|
||||||
@ -113,3 +114,6 @@ class TunnelTermination(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ChangeLo
|
|||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return self.tunnel.get_absolute_url()
|
return self.tunnel.get_absolute_url()
|
||||||
|
|
||||||
|
def get_role_color(self):
|
||||||
|
return TunnelTerminationRoleChoices.colors.get(self.role)
|
||||||
|
@ -21,9 +21,6 @@ class TunnelTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
status = columns.ChoiceFieldColumn(
|
status = columns.ChoiceFieldColumn(
|
||||||
verbose_name=_('Status')
|
verbose_name=_('Status')
|
||||||
)
|
)
|
||||||
encapsulation = columns.ChoiceFieldColumn(
|
|
||||||
verbose_name=_('Encapsulation')
|
|
||||||
)
|
|
||||||
ipsec_profile = tables.Column(
|
ipsec_profile = tables.Column(
|
||||||
verbose_name=_('IPSec profile'),
|
verbose_name=_('IPSec profile'),
|
||||||
linkify=True
|
linkify=True
|
||||||
@ -47,7 +44,7 @@ class TunnelTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
'pk', 'id', 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'tenant_group', 'preshared_key',
|
'pk', 'id', 'name', 'status', 'encapsulation', 'ipsec_profile', 'tenant', 'tenant_group', 'preshared_key',
|
||||||
'tunnel_id', 'termination_count', 'description', 'comments', 'tags', 'created', 'last_updated',
|
'tunnel_id', 'termination_count', 'description', 'comments', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'name', 'status', 'encapsulation', 'tenant', 'termination_count')
|
default_columns = ('pk', 'name', 'status', 'encapsulation', 'tenant', 'terminations_count')
|
||||||
|
|
||||||
|
|
||||||
class TunnelTerminationTable(TenancyColumnsMixin, NetBoxTable):
|
class TunnelTerminationTable(TenancyColumnsMixin, NetBoxTable):
|
||||||
|
@ -67,11 +67,6 @@ class TunnelTerminationListView(generic.ObjectListView):
|
|||||||
table = tables.TunnelTerminationTable
|
table = tables.TunnelTerminationTable
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(TunnelTermination)
|
|
||||||
class TunnelTerminationView(generic.ObjectView):
|
|
||||||
queryset = TunnelTermination.objects.all()
|
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(TunnelTermination, 'edit')
|
@register_model_view(TunnelTermination, 'edit')
|
||||||
class TunnelTerminationEditView(generic.ObjectEditView):
|
class TunnelTerminationEditView(generic.ObjectEditView):
|
||||||
queryset = TunnelTermination.objects.all()
|
queryset = TunnelTermination.objects.all()
|
||||||
|
Loading…
Reference in New Issue
Block a user