mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-23 07:56:44 -06:00
Add UI view tests
This commit is contained in:
parent
f600f908cf
commit
c814e763a1
55
netbox/templates/vpn/tunneltermination.html
Normal file
55
netbox/templates/vpn/tunneltermination.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{% 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 Termination" %}</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Tunnel" %}</th>
|
||||||
|
<td>{{ object.tunnel|linkify }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Role" %}</th>
|
||||||
|
<td>{{ object.get_role_display }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
{% if object.interface.device %}
|
||||||
|
{% trans "Device" %}
|
||||||
|
{% elif object.interface.virtual_machine %}
|
||||||
|
{% trans "Virtual Machine" %}
|
||||||
|
{% endif %}
|
||||||
|
</th>
|
||||||
|
<td>{{ object.interface.parent_object|linkify }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Interface" %}</th>
|
||||||
|
<td>{{ object.interface|linkify }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Outside IP" %}</th>
|
||||||
|
<td>{{ object.outside_ip|linkify|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' %}
|
||||||
|
{% plugin_right_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
{% plugin_full_width_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -4,7 +4,7 @@ from dcim.models import Device, Interface
|
|||||||
from ipam.models import IPAddress
|
from ipam.models import IPAddress
|
||||||
from netbox.forms import NetBoxModelImportForm
|
from netbox.forms import NetBoxModelImportForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms.fields import CSVChoiceField, CSVModelChoiceField
|
from utilities.forms.fields import CSVChoiceField, CSVModelChoiceField, CSVModelMultipleChoiceField
|
||||||
from virtualization.models import VirtualMachine, VMInterface
|
from virtualization.models import VirtualMachine, VMInterface
|
||||||
from vpn.choices import *
|
from vpn.choices import *
|
||||||
from vpn.models import *
|
from vpn.models import *
|
||||||
@ -34,6 +34,7 @@ class TunnelImportForm(NetBoxModelImportForm):
|
|||||||
ipsec_profile = CSVModelChoiceField(
|
ipsec_profile = CSVModelChoiceField(
|
||||||
label=_('IPSec profile'),
|
label=_('IPSec profile'),
|
||||||
queryset=IPSecProfile.objects.all(),
|
queryset=IPSecProfile.objects.all(),
|
||||||
|
required=False,
|
||||||
to_field_name='name'
|
to_field_name='name'
|
||||||
)
|
)
|
||||||
tenant = CSVModelChoiceField(
|
tenant = CSVModelChoiceField(
|
||||||
@ -87,6 +88,7 @@ class TunnelTerminationImportForm(NetBoxModelImportForm):
|
|||||||
outside_ip = CSVModelChoiceField(
|
outside_ip = CSVModelChoiceField(
|
||||||
label=_('Outside IP'),
|
label=_('Outside IP'),
|
||||||
queryset=IPAddress.objects.all(),
|
queryset=IPAddress.objects.all(),
|
||||||
|
required=False,
|
||||||
to_field_name='name'
|
to_field_name='name'
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -111,6 +113,14 @@ class TunnelTerminationImportForm(NetBoxModelImportForm):
|
|||||||
**{f"virtual_machine__{self.fields['virtual_machine'].to_field_name}": data['virtual_machine']}
|
**{f"virtual_machine__{self.fields['virtual_machine'].to_field_name}": data['virtual_machine']}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
|
# Set interface assignment
|
||||||
|
if self.cleaned_data.get('interface'):
|
||||||
|
self.instance.interface = self.cleaned_data['interface']
|
||||||
|
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class IKEProposalImportForm(NetBoxModelImportForm):
|
class IKEProposalImportForm(NetBoxModelImportForm):
|
||||||
authentication_method = CSVChoiceField(
|
authentication_method = CSVChoiceField(
|
||||||
@ -121,7 +131,7 @@ class IKEProposalImportForm(NetBoxModelImportForm):
|
|||||||
label=_('Encryption algorithm'),
|
label=_('Encryption algorithm'),
|
||||||
choices=EncryptionAlgorithmChoices
|
choices=EncryptionAlgorithmChoices
|
||||||
)
|
)
|
||||||
authentication_algorithmn = CSVChoiceField(
|
authentication_algorithm = CSVChoiceField(
|
||||||
label=_('Authentication algorithm'),
|
label=_('Authentication algorithm'),
|
||||||
choices=AuthenticationAlgorithmChoices
|
choices=AuthenticationAlgorithmChoices
|
||||||
)
|
)
|
||||||
@ -133,7 +143,7 @@ class IKEProposalImportForm(NetBoxModelImportForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = IKEProposal
|
model = IKEProposal
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'description', 'authentication_method', 'encryption_algorithm', 'authentication_algorithmn',
|
'name', 'description', 'authentication_method', 'encryption_algorithm', 'authentication_algorithm',
|
||||||
'group', 'sa_lifetime', 'tags',
|
'group', 'sa_lifetime', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -147,7 +157,11 @@ class IKEPolicyImportForm(NetBoxModelImportForm):
|
|||||||
label=_('Mode'),
|
label=_('Mode'),
|
||||||
choices=IKEModeChoices
|
choices=IKEModeChoices
|
||||||
)
|
)
|
||||||
# TODO: M2M field for proposals
|
proposals = CSVModelMultipleChoiceField(
|
||||||
|
queryset=IKEProposal.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
help_text=_('IKE proposal(s)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IKEPolicy
|
model = IKEPolicy
|
||||||
@ -161,7 +175,7 @@ class IPSecProposalImportForm(NetBoxModelImportForm):
|
|||||||
label=_('Encryption algorithm'),
|
label=_('Encryption algorithm'),
|
||||||
choices=EncryptionAlgorithmChoices
|
choices=EncryptionAlgorithmChoices
|
||||||
)
|
)
|
||||||
authentication_algorithmn = CSVChoiceField(
|
authentication_algorithm = CSVChoiceField(
|
||||||
label=_('Authentication algorithm'),
|
label=_('Authentication algorithm'),
|
||||||
choices=AuthenticationAlgorithmChoices
|
choices=AuthenticationAlgorithmChoices
|
||||||
)
|
)
|
||||||
@ -169,7 +183,7 @@ class IPSecProposalImportForm(NetBoxModelImportForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = IPSecProposal
|
model = IPSecProposal
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'description', 'encryption_algorithm', 'authentication_algorithmn', 'sa_lifetime_seconds',
|
'name', 'description', 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds',
|
||||||
'sa_lifetime_data', 'tags',
|
'sa_lifetime_data', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -179,7 +193,11 @@ class IPSecPolicyImportForm(NetBoxModelImportForm):
|
|||||||
label=_('PFS group'),
|
label=_('PFS group'),
|
||||||
choices=DHGroupChoices
|
choices=DHGroupChoices
|
||||||
)
|
)
|
||||||
# TODO: M2M field for proposals
|
proposals = CSVModelMultipleChoiceField(
|
||||||
|
queryset=IPSecProposal.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
help_text=_('IPSec proposal(s)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPSecPolicy
|
model = IPSecPolicy
|
||||||
|
@ -6,6 +6,7 @@ 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, DynamicModelMultipleChoiceField
|
from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
||||||
|
from utilities.forms.utils import add_blank_choice
|
||||||
from utilities.forms.widgets import HTMXSelect
|
from utilities.forms.widgets import HTMXSelect
|
||||||
from virtualization.models import VirtualMachine, VMInterface
|
from virtualization.models import VirtualMachine, VMInterface
|
||||||
from vpn.choices import *
|
from vpn.choices import *
|
||||||
@ -20,7 +21,6 @@ __all__ = (
|
|||||||
'TunnelCreateForm',
|
'TunnelCreateForm',
|
||||||
'TunnelForm',
|
'TunnelForm',
|
||||||
'TunnelTerminationForm',
|
'TunnelTerminationForm',
|
||||||
'TunnelTerminationCreateForm',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -49,21 +49,25 @@ class TunnelForm(TenancyForm, NetBoxModelForm):
|
|||||||
class TunnelCreateForm(TunnelForm):
|
class TunnelCreateForm(TunnelForm):
|
||||||
# First termination
|
# First termination
|
||||||
termination1_role = forms.ChoiceField(
|
termination1_role = forms.ChoiceField(
|
||||||
choices=TunnelTerminationRoleChoices,
|
choices=add_blank_choice(TunnelTerminationRoleChoices),
|
||||||
|
required=False,
|
||||||
label=_('Role')
|
label=_('Role')
|
||||||
)
|
)
|
||||||
termination1_type = forms.ChoiceField(
|
termination1_type = forms.ChoiceField(
|
||||||
choices=TunnelTerminationTypeChoices,
|
choices=TunnelTerminationTypeChoices,
|
||||||
|
required=False,
|
||||||
widget=HTMXSelect(),
|
widget=HTMXSelect(),
|
||||||
label=_('Type')
|
label=_('Type')
|
||||||
)
|
)
|
||||||
termination1_parent = DynamicModelChoiceField(
|
termination1_parent = DynamicModelChoiceField(
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
|
required=False,
|
||||||
selector=True,
|
selector=True,
|
||||||
label=_('Device')
|
label=_('Device')
|
||||||
)
|
)
|
||||||
termination1_interface = DynamicModelChoiceField(
|
termination1_interface = DynamicModelChoiceField(
|
||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
|
required=False,
|
||||||
label=_('Interface'),
|
label=_('Interface'),
|
||||||
query_params={
|
query_params={
|
||||||
'device_id': '$termination1_parent',
|
'device_id': '$termination1_parent',
|
||||||
@ -80,7 +84,7 @@ class TunnelCreateForm(TunnelForm):
|
|||||||
|
|
||||||
# Second termination
|
# Second termination
|
||||||
termination2_role = forms.ChoiceField(
|
termination2_role = forms.ChoiceField(
|
||||||
choices=TunnelTerminationRoleChoices,
|
choices=add_blank_choice(TunnelTerminationRoleChoices),
|
||||||
required=False,
|
required=False,
|
||||||
label=_('Role')
|
label=_('Role')
|
||||||
)
|
)
|
||||||
@ -155,25 +159,27 @@ class TunnelCreateForm(TunnelForm):
|
|||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
# Check that all required parameters have been set for the second termination (if any)
|
# Validate attributes for each termination (if any)
|
||||||
termination2_required_parameters = (
|
for term in ('termination1', 'termination2'):
|
||||||
'termination2_role', 'termination2_type', 'termination2_parent', 'termination2_interface',
|
required_parameters = (
|
||||||
|
f'{term}_role', f'{term}_parent', f'{term}_interface',
|
||||||
)
|
)
|
||||||
termination2_parameters = (
|
parameters = (
|
||||||
*termination2_required_parameters,
|
*required_parameters,
|
||||||
'termination2_outside_ip',
|
f'{term}_outside_ip',
|
||||||
)
|
)
|
||||||
if any([self.cleaned_data[param] for param in termination2_parameters]):
|
if any([self.cleaned_data[param] for param in parameters]):
|
||||||
for param in termination2_required_parameters:
|
for param in required_parameters:
|
||||||
if not self.cleaned_data[param]:
|
if not self.cleaned_data[param]:
|
||||||
raise forms.ValidationError({
|
raise forms.ValidationError({
|
||||||
param: _("This parameter is required when defining a second termination.")
|
param: _("This parameter is required when defining a termination.")
|
||||||
})
|
})
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
instance = super().save(*args, **kwargs)
|
instance = super().save(*args, **kwargs)
|
||||||
|
|
||||||
# Create first termination
|
# Create first termination
|
||||||
|
if self.cleaned_data['termination1_interface']:
|
||||||
TunnelTermination.objects.create(
|
TunnelTermination.objects.create(
|
||||||
tunnel=instance,
|
tunnel=instance,
|
||||||
role=self.cleaned_data['termination1_role'],
|
role=self.cleaned_data['termination1_role'],
|
||||||
@ -182,7 +188,7 @@ class TunnelCreateForm(TunnelForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Create second termination, if defined
|
# Create second termination, if defined
|
||||||
if self.cleaned_data['termination2_role']:
|
if self.cleaned_data['termination2_interface']:
|
||||||
TunnelTermination.objects.create(
|
TunnelTermination.objects.create(
|
||||||
tunnel=instance,
|
tunnel=instance,
|
||||||
role=self.cleaned_data['termination2_role'],
|
role=self.cleaned_data['termination2_role'],
|
||||||
@ -194,20 +200,6 @@ class TunnelCreateForm(TunnelForm):
|
|||||||
|
|
||||||
|
|
||||||
class TunnelTerminationForm(NetBoxModelForm):
|
class TunnelTerminationForm(NetBoxModelForm):
|
||||||
outside_ip = DynamicModelChoiceField(
|
|
||||||
queryset=IPAddress.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Outside IP')
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = TunnelTermination
|
|
||||||
fields = [
|
|
||||||
'role', 'outside_ip', 'tags',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class TunnelTerminationCreateForm(NetBoxModelForm):
|
|
||||||
tunnel = DynamicModelChoiceField(
|
tunnel = DynamicModelChoiceField(
|
||||||
queryset=Tunnel.objects.all()
|
queryset=Tunnel.objects.all()
|
||||||
)
|
)
|
||||||
@ -261,11 +253,15 @@ class TunnelTerminationCreateForm(NetBoxModelForm):
|
|||||||
'virtual_machine_id': '$parent',
|
'virtual_machine_id': '$parent',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if self.instance.pk:
|
||||||
|
self.fields['parent'].initial = self.instance.interface.parent_object
|
||||||
|
self.fields['interface'].initial = self.instance.interface
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
# Assign the interface
|
# Assign the interface
|
||||||
self.instance.interface = self.cleaned_data['interface']
|
self.instance.interface = self.cleaned_data.get('interface')
|
||||||
|
|
||||||
|
|
||||||
class IKEProposalForm(NetBoxModelForm):
|
class IKEProposalForm(NetBoxModelForm):
|
||||||
|
@ -119,7 +119,7 @@ class TunnelTermination(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ChangeLo
|
|||||||
return f'{self.tunnel}: Termination {self.pk}'
|
return f'{self.tunnel}: Termination {self.pk}'
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return self.tunnel.get_absolute_url()
|
return reverse('vpn:tunneltermination', args=[self.pk])
|
||||||
|
|
||||||
def get_role_color(self):
|
def get_role_color(self):
|
||||||
return TunnelTerminationRoleChoices.colors.get(self.role)
|
return TunnelTerminationRoleChoices.colors.get(self.role)
|
||||||
@ -128,7 +128,7 @@ class TunnelTermination(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ChangeLo
|
|||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
# Check that the selected Interface is not already attached to a Tunnel
|
# Check that the selected Interface is not already attached to a Tunnel
|
||||||
if self.interface.tunnel_termination and self.interface.tunnel_termination.pk != self.pk:
|
if getattr(self.interface, 'tunnel_termination', None) and self.interface.tunnel_termination.pk != self.pk:
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'interface': _("Interface {name} is already attached to a tunnel ({tunnel}).").format(
|
'interface': _("Interface {name} is already attached to a tunnel ({tunnel}).").format(
|
||||||
name=self.interface.name,
|
name=self.interface.name,
|
||||||
|
@ -89,7 +89,7 @@ class TunnelTerminationTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
'pk', 'id', 'tunnel', 'role', 'interface_parent', 'interface', 'ip_addresses', 'outside_ip', 'tags',
|
'pk', 'id', 'tunnel', 'role', 'interface_parent', 'interface', 'ip_addresses', 'outside_ip', 'tags',
|
||||||
'created', 'last_updated',
|
'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'tunnel', 'role', 'interface_parent', 'interface', 'ip_addresses', 'outside_ip')
|
default_columns = ('pk', 'id', 'tunnel', 'role', 'interface_parent', 'interface', 'ip_addresses', 'outside_ip')
|
||||||
|
|
||||||
|
|
||||||
class IKEProposalTable(NetBoxTable):
|
class IKEProposalTable(NetBoxTable):
|
||||||
|
509
netbox/vpn/tests/test_views.py
Normal file
509
netbox/vpn/tests/test_views.py
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
|
from dcim.choices import InterfaceTypeChoices
|
||||||
|
from dcim.models import Interface
|
||||||
|
from vpn.choices import *
|
||||||
|
from vpn.models import *
|
||||||
|
from utilities.testing import ViewTestCases, create_tags, create_test_device
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = Tunnel
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
tunnels = (
|
||||||
|
Tunnel(
|
||||||
|
name='Tunnel 1',
|
||||||
|
status=TunnelStatusChoices.STATUS_ACTIVE,
|
||||||
|
encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
|
||||||
|
),
|
||||||
|
Tunnel(
|
||||||
|
name='Tunnel 2',
|
||||||
|
status=TunnelStatusChoices.STATUS_ACTIVE,
|
||||||
|
encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
|
||||||
|
),
|
||||||
|
Tunnel(
|
||||||
|
name='Tunnel 3',
|
||||||
|
status=TunnelStatusChoices.STATUS_ACTIVE,
|
||||||
|
encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
|
||||||
|
),
|
||||||
|
)
|
||||||
|
Tunnel.objects.bulk_create(tunnels)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'Tunnel X',
|
||||||
|
'description': 'New tunnel',
|
||||||
|
'status': TunnelStatusChoices.STATUS_PLANNED,
|
||||||
|
'encapsulation': TunnelEncapsulationChoices.ENCAP_GRE,
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,status,encapsulation",
|
||||||
|
"Tunnel 4,planned,gre",
|
||||||
|
"Tunnel 5,planned,gre",
|
||||||
|
"Tunnel 6,planned,gre",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,status,encapsulation",
|
||||||
|
f"{tunnels[0].pk},active,ip-ip",
|
||||||
|
f"{tunnels[1].pk},active,ip-ip",
|
||||||
|
f"{tunnels[2].pk},active,ip-ip",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
'status': TunnelStatusChoices.STATUS_DISABLED,
|
||||||
|
'encapsulation': TunnelEncapsulationChoices.ENCAP_GRE,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TunnelTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = TunnelTermination
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
device = create_test_device('Device 1')
|
||||||
|
interfaces = (
|
||||||
|
Interface(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=device, name='Interface 2', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=device, name='Interface 3', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=device, name='Interface 4', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=device, name='Interface 5', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=device, name='Interface 6', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=device, name='Interface 7', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
)
|
||||||
|
Interface.objects.bulk_create(interfaces)
|
||||||
|
|
||||||
|
tunnel = Tunnel.objects.create(
|
||||||
|
name='Tunnel 1',
|
||||||
|
status=TunnelStatusChoices.STATUS_ACTIVE,
|
||||||
|
encapsulation=TunnelEncapsulationChoices.ENCAP_IP_IP
|
||||||
|
)
|
||||||
|
|
||||||
|
tunnel_terminations = (
|
||||||
|
TunnelTermination(
|
||||||
|
tunnel=tunnel,
|
||||||
|
role=TunnelTerminationRoleChoices.ROLE_HUB,
|
||||||
|
interface=interfaces[0]
|
||||||
|
),
|
||||||
|
TunnelTermination(
|
||||||
|
tunnel=tunnel,
|
||||||
|
role=TunnelTerminationRoleChoices.ROLE_SPOKE,
|
||||||
|
interface=interfaces[1]
|
||||||
|
),
|
||||||
|
TunnelTermination(
|
||||||
|
tunnel=tunnel,
|
||||||
|
role=TunnelTerminationRoleChoices.ROLE_SPOKE,
|
||||||
|
interface=interfaces[2]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
TunnelTermination.objects.bulk_create(tunnel_terminations)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'tunnel': tunnel.pk,
|
||||||
|
'role': TunnelTerminationRoleChoices.ROLE_PEER,
|
||||||
|
'type': TunnelTerminationTypeChoices.TYPE_DEVICE,
|
||||||
|
'parent': device.pk,
|
||||||
|
# TODO: Solve for GFK validation
|
||||||
|
'interface': interfaces[6].pk,
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.csv_data = (
|
||||||
|
"tunnel,role,device,interface",
|
||||||
|
"Tunnel 1,peer,Device 1,Interface 4",
|
||||||
|
"Tunnel 1,peer,Device 1,Interface 5",
|
||||||
|
"Tunnel 1,peer,Device 1,Interface 6",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,role",
|
||||||
|
f"{tunnel_terminations[0].pk},peer",
|
||||||
|
f"{tunnel_terminations[1].pk},peer",
|
||||||
|
f"{tunnel_terminations[2].pk},peer",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'role': TunnelTerminationRoleChoices.ROLE_PEER,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IKEProposalTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = IKEProposal
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
ike_proposals = (
|
||||||
|
IKEProposal(
|
||||||
|
name='IKE Proposal 1',
|
||||||
|
authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
IKEProposal(
|
||||||
|
name='IKE Proposal 2',
|
||||||
|
authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
IKEProposal(
|
||||||
|
name='IKE Proposal 3',
|
||||||
|
authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IKEProposal.objects.bulk_create(ike_proposals)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'IKE Proposal X',
|
||||||
|
'authentication_method': AuthenticationMethodChoices.CERTIFICATES,
|
||||||
|
'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC,
|
||||||
|
'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
|
||||||
|
'group': DHGroupChoices.GROUP_19,
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,authentication_method,encryption_algorithm,authentication_algorithm,group",
|
||||||
|
"IKE Proposal 4,preshared-keys,aes-128-cbc,hmac-sha1,14",
|
||||||
|
"IKE Proposal 5,preshared-keys,aes-128-cbc,hmac-sha1,14",
|
||||||
|
"IKE Proposal 6,preshared-keys,aes-128-cbc,hmac-sha1,14",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,description",
|
||||||
|
f"{ike_proposals[0].pk},New description",
|
||||||
|
f"{ike_proposals[1].pk},New description",
|
||||||
|
f"{ike_proposals[2].pk},New description",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
'authentication_method': AuthenticationMethodChoices.CERTIFICATES,
|
||||||
|
'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC,
|
||||||
|
'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
|
||||||
|
'group': DHGroupChoices.GROUP_19
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IKEPolicyTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = IKEPolicy
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
ike_proposals = (
|
||||||
|
IKEProposal(
|
||||||
|
name='IKE Proposal 1',
|
||||||
|
authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
IKEProposal(
|
||||||
|
name='IKE Proposal 2',
|
||||||
|
authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IKEProposal.objects.bulk_create(ike_proposals)
|
||||||
|
|
||||||
|
ike_policies = (
|
||||||
|
IKEPolicy(
|
||||||
|
name='IKE Policy 1',
|
||||||
|
version=IKEVersionChoices.VERSION_1,
|
||||||
|
mode=IKEModeChoices.MAIN,
|
||||||
|
),
|
||||||
|
IKEPolicy(
|
||||||
|
name='IKE Policy 2',
|
||||||
|
version=IKEVersionChoices.VERSION_1,
|
||||||
|
mode=IKEModeChoices.MAIN,
|
||||||
|
),
|
||||||
|
IKEPolicy(
|
||||||
|
name='IKE Policy 3',
|
||||||
|
version=IKEVersionChoices.VERSION_1,
|
||||||
|
mode=IKEModeChoices.MAIN,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IKEPolicy.objects.bulk_create(ike_policies)
|
||||||
|
for ike_policy in ike_policies:
|
||||||
|
ike_policy.proposals.set(ike_proposals)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'IKE Policy X',
|
||||||
|
'version': IKEVersionChoices.VERSION_2,
|
||||||
|
'mode': IKEModeChoices.AGGRESSIVE,
|
||||||
|
'proposals': [p.pk for p in ike_proposals],
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
ike_proposal_names = ','.join([p.name for p in ike_proposals])
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,version,mode,proposals",
|
||||||
|
f"IKE Proposal 4,2,aggressive,\"{ike_proposal_names}\"",
|
||||||
|
f"IKE Proposal 5,2,aggressive,\"{ike_proposal_names}\"",
|
||||||
|
f"IKE Proposal 6,2,aggressive,\"{ike_proposal_names}\"",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,description",
|
||||||
|
f"{ike_policies[0].pk},New description",
|
||||||
|
f"{ike_policies[1].pk},New description",
|
||||||
|
f"{ike_policies[2].pk},New description",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
'version': IKEVersionChoices.VERSION_2,
|
||||||
|
'mode': IKEModeChoices.AGGRESSIVE,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecProposalTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = IPSecProposal
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
ipsec_proposals = (
|
||||||
|
IPSecProposal(
|
||||||
|
name='IPSec Proposal 1',
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
),
|
||||||
|
IPSecProposal(
|
||||||
|
name='IPSec Proposal 2',
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
),
|
||||||
|
IPSecProposal(
|
||||||
|
name='IPSec Proposal 3',
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IPSecProposal.objects.bulk_create(ipsec_proposals)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'IPSec Proposal X',
|
||||||
|
'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC,
|
||||||
|
'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
|
||||||
|
'sa_lifetime_seconds': 3600,
|
||||||
|
'sa_lifetime_data': 1000000,
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,encryption_algorithm,authentication_algorithm,sa_lifetime_seconds,sa_lifetime_data",
|
||||||
|
"IKE Proposal 4,aes-128-cbc,hmac-sha1,3600,1000000",
|
||||||
|
"IKE Proposal 5,aes-128-cbc,hmac-sha1,3600,1000000",
|
||||||
|
"IKE Proposal 6,aes-128-cbc,hmac-sha1,3600,1000000",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,description",
|
||||||
|
f"{ipsec_proposals[0].pk},New description",
|
||||||
|
f"{ipsec_proposals[1].pk},New description",
|
||||||
|
f"{ipsec_proposals[2].pk},New description",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
'encryption_algorithm': EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC,
|
||||||
|
'authentication_algorithm': AuthenticationAlgorithmChoices.AUTH_HMAC_SHA256,
|
||||||
|
'sa_lifetime_seconds': 3600,
|
||||||
|
'sa_lifetime_data': 1000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecPolicyTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = IPSecPolicy
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
ipsec_proposals = (
|
||||||
|
IPSecProposal(
|
||||||
|
name='IPSec Policy 1',
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
|
||||||
|
),
|
||||||
|
IPSecProposal(
|
||||||
|
name='IPSec Proposal 2',
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IPSecProposal.objects.bulk_create(ipsec_proposals)
|
||||||
|
|
||||||
|
ipsec_policies = (
|
||||||
|
IPSecPolicy(
|
||||||
|
name='IPSec Policy 1',
|
||||||
|
pfs_group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
IPSecPolicy(
|
||||||
|
name='IPSec Policy 2',
|
||||||
|
pfs_group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
IPSecPolicy(
|
||||||
|
name='IPSec Policy 3',
|
||||||
|
pfs_group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IPSecPolicy.objects.bulk_create(ipsec_policies)
|
||||||
|
for ipsec_policy in ipsec_policies:
|
||||||
|
ipsec_policy.proposals.set(ipsec_proposals)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'IPSec Policy X',
|
||||||
|
'pfs_group': DHGroupChoices.GROUP_5,
|
||||||
|
'proposals': [p.pk for p in ipsec_proposals],
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
ipsec_proposal_names = ','.join([p.name for p in ipsec_proposals])
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,pfs_group,proposals",
|
||||||
|
f"IKE Proposal 4,19,\"{ipsec_proposal_names}\"",
|
||||||
|
f"IKE Proposal 5,19,\"{ipsec_proposal_names}\"",
|
||||||
|
f"IKE Proposal 6,19,\"{ipsec_proposal_names}\"",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,description",
|
||||||
|
f"{ipsec_policies[0].pk},New description",
|
||||||
|
f"{ipsec_policies[1].pk},New description",
|
||||||
|
f"{ipsec_policies[2].pk},New description",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
'pfs_group': DHGroupChoices.GROUP_5,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IPSecProfileTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
|
model = IPSecProfile
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
ike_proposal = IKEProposal.objects.create(
|
||||||
|
name='IKE Proposal 1',
|
||||||
|
authentication_method=AuthenticationMethodChoices.PRESHARED_KEYS,
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1,
|
||||||
|
group=DHGroupChoices.GROUP_14
|
||||||
|
)
|
||||||
|
|
||||||
|
ipsec_proposal = IPSecProposal.objects.create(
|
||||||
|
name='IPSec Proposal 1',
|
||||||
|
encryption_algorithm=EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC,
|
||||||
|
authentication_algorithm=AuthenticationAlgorithmChoices.AUTH_HMAC_SHA1
|
||||||
|
)
|
||||||
|
|
||||||
|
ike_policies = (
|
||||||
|
IKEPolicy(
|
||||||
|
name='IKE Policy 1',
|
||||||
|
version=IKEVersionChoices.VERSION_1,
|
||||||
|
mode=IKEModeChoices.MAIN,
|
||||||
|
),
|
||||||
|
IKEPolicy(
|
||||||
|
name='IKE Policy 2',
|
||||||
|
version=IKEVersionChoices.VERSION_1,
|
||||||
|
mode=IKEModeChoices.MAIN,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IKEPolicy.objects.bulk_create(ike_policies)
|
||||||
|
for ike_policy in ike_policies:
|
||||||
|
ike_policy.proposals.add(ike_proposal)
|
||||||
|
|
||||||
|
ipsec_policies = (
|
||||||
|
IPSecPolicy(
|
||||||
|
name='IPSec Policy 1',
|
||||||
|
pfs_group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
IPSecPolicy(
|
||||||
|
name='IPSec Policy 2',
|
||||||
|
pfs_group=DHGroupChoices.GROUP_14
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IPSecPolicy.objects.bulk_create(ipsec_policies)
|
||||||
|
for ipsec_policy in ipsec_policies:
|
||||||
|
ipsec_policy.proposals.add(ipsec_proposal)
|
||||||
|
|
||||||
|
ipsec_profiles = (
|
||||||
|
IPSecProfile(
|
||||||
|
name='IPSec Profile 1',
|
||||||
|
mode=IPSecModeChoices.ESP,
|
||||||
|
ike_policy=ike_policies[0],
|
||||||
|
ipsec_policy=ipsec_policies[0]
|
||||||
|
),
|
||||||
|
IPSecProfile(
|
||||||
|
name='IPSec Profile 2',
|
||||||
|
mode=IPSecModeChoices.ESP,
|
||||||
|
ike_policy=ike_policies[0],
|
||||||
|
ipsec_policy=ipsec_policies[0]
|
||||||
|
),
|
||||||
|
IPSecProfile(
|
||||||
|
name='IPSec Profile 3',
|
||||||
|
mode=IPSecModeChoices.ESP,
|
||||||
|
ike_policy=ike_policies[0],
|
||||||
|
ipsec_policy=ipsec_policies[0]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
IPSecProfile.objects.bulk_create(ipsec_profiles)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'IPSec Profile X',
|
||||||
|
'mode': IPSecModeChoices.AH,
|
||||||
|
'ike_policy': ike_policies[1].pk,
|
||||||
|
'ipsec_policy': ipsec_policies[1].pk,
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,mode,ike_policy,ipsec_policy",
|
||||||
|
f"IKE Proposal 4,ah,IKE Policy 2,IPSec Policy 2",
|
||||||
|
f"IKE Proposal 5,ah,IKE Policy 2,IPSec Policy 2",
|
||||||
|
f"IKE Proposal 6,ah,IKE Policy 2,IPSec Policy 2",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,description",
|
||||||
|
f"{ipsec_profiles[0].pk},New description",
|
||||||
|
f"{ipsec_profiles[1].pk},New description",
|
||||||
|
f"{ipsec_profiles[2].pk},New description",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
'mode': IPSecModeChoices.AH,
|
||||||
|
'ike_policy': ike_policies[1].pk,
|
||||||
|
'ipsec_policy': ipsec_policies[1].pk,
|
||||||
|
}
|
@ -75,19 +75,16 @@ 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()
|
||||||
form = forms.TunnelTerminationForm
|
form = forms.TunnelTerminationForm
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
|
|
||||||
# If creating a new Tunnel, use the creation form
|
|
||||||
if 'pk' not in kwargs:
|
|
||||||
self.form = forms.TunnelTerminationCreateForm
|
|
||||||
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(TunnelTermination, 'delete')
|
@register_model_view(TunnelTermination, 'delete')
|
||||||
class TunnelTerminationDeleteView(generic.ObjectDeleteView):
|
class TunnelTerminationDeleteView(generic.ObjectDeleteView):
|
||||||
|
Loading…
Reference in New Issue
Block a user