mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-27 07:02:26 +00:00
Merge branch 'switch_conf' into 'dev'
Switch conf See merge request federez/re2o!308
This commit is contained in:
commit
8045645502
26 changed files with 1315 additions and 28 deletions
|
@ -153,7 +153,8 @@ class VlanSerializer(NamespacedHMSerializer):
|
|||
"""
|
||||
class Meta:
|
||||
model = machines.Vlan
|
||||
fields = ('vlan_id', 'name', 'comment', 'api_url')
|
||||
fields = ('vlan_id', 'name', 'comment', 'arp_protect', 'dhcp_snooping',
|
||||
'dhcpv6_snooping', 'igmp', 'mld', 'api_url')
|
||||
|
||||
|
||||
class NasSerializer(NamespacedHMSerializer):
|
||||
|
@ -310,6 +311,16 @@ class OuverturePortSerializer(NamespacedHMSerializer):
|
|||
fields = ('begin', 'end', 'port_list', 'protocole', 'io', 'api_url')
|
||||
|
||||
|
||||
class RoleSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
servers = InterfaceSerializer(read_only=True, many=True)
|
||||
|
||||
class Meta:
|
||||
model = machines.Role
|
||||
fields = ('role_type', 'servers', 'api_url')
|
||||
|
||||
|
||||
# PREFERENCES
|
||||
|
||||
|
||||
|
@ -338,11 +349,15 @@ class OptionalMachineSerializer(NamespacedHMSerializer):
|
|||
class OptionalTopologieSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalTopologie` objects.
|
||||
"""
|
||||
switchs_management_interface_ip = serializers.CharField()
|
||||
|
||||
class Meta:
|
||||
model = preferences.OptionalTopologie
|
||||
fields = ('radius_general_policy', 'vlan_decision_ok',
|
||||
'vlan_decision_nok')
|
||||
'vlan_decision_nok', 'switchs_ip_type', 'switchs_web_management',
|
||||
'switchs_web_management_ssl', 'switchs_rest_management',
|
||||
'switchs_management_utils', 'switchs_management_interface_ip',
|
||||
'provision_switchs_enabled', 'switchs_provision', 'switchs_management_sftp_creds')
|
||||
|
||||
|
||||
class GeneralOptionSerializer(NamespacedHMSerializer):
|
||||
|
@ -467,16 +482,30 @@ class BuildingSerializer(NamespacedHMSerializer):
|
|||
class SwitchPortSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Port` objects
|
||||
"""
|
||||
|
||||
get_port_profil = NamespacedHIField(view_name='portprofile-detail', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = topologie.Port
|
||||
fields = ('switch', 'port', 'room', 'machine_interface', 'related',
|
||||
'custom_profile', 'state', 'details', 'api_url')
|
||||
'custom_profile', 'state', 'get_port_profil', 'details', 'api_url')
|
||||
extra_kwargs = {
|
||||
'related': {'view_name': 'switchport-detail'},
|
||||
'api_url': {'view_name': 'switchport-detail'},
|
||||
}
|
||||
|
||||
|
||||
class PortProfileSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Room` objects
|
||||
"""
|
||||
class Meta:
|
||||
model = topologie.PortProfile
|
||||
fields = ('name', 'profil_default', 'vlan_untagged', 'vlan_tagged',
|
||||
'radius_type', 'radius_mode', 'speed', 'mac_limit', 'flow_control',
|
||||
'dhcp_snooping', 'dhcpv6_snooping', 'dhcpv6_snooping', 'arp_protect',
|
||||
'ra_guard', 'loop_protect', 'api_url')
|
||||
|
||||
|
||||
class RoomSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `topologie.models.Room` objects
|
||||
"""
|
||||
|
@ -644,6 +673,89 @@ class ServiceRegenSerializer(NamespacedHMSerializer):
|
|||
'api_url': {'view_name': 'serviceregen-detail'}
|
||||
}
|
||||
|
||||
# Switches et ports
|
||||
|
||||
class InterfaceVlanSerializer(NamespacedHMSerializer):
|
||||
domain = serializers.CharField(read_only=True)
|
||||
ipv4 = serializers.CharField(read_only=True)
|
||||
ipv6 = Ipv6ListSerializer(read_only=True, many=True)
|
||||
vlan_id = serializers.IntegerField(source='type.ip_type.vlan.vlan_id', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = machines.Interface
|
||||
fields = ('ipv4', 'ipv6', 'domain', 'vlan_id')
|
||||
|
||||
class InterfaceRoleSerializer(NamespacedHMSerializer):
|
||||
interface = InterfaceVlanSerializer(source='machine.interface_set', read_only=True, many=True)
|
||||
|
||||
class Meta:
|
||||
model = machines.Interface
|
||||
fields = ('interface',)
|
||||
|
||||
|
||||
class RoleSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
servers = InterfaceRoleSerializer(read_only=True, many=True)
|
||||
|
||||
class Meta:
|
||||
model = machines.Role
|
||||
fields = ('role_type', 'servers', 'specific_role')
|
||||
|
||||
|
||||
class VlanPortSerializer(NamespacedHMSerializer):
|
||||
class Meta:
|
||||
model = machines.Vlan
|
||||
fields = ('vlan_id', 'name')
|
||||
|
||||
|
||||
class ProfilSerializer(NamespacedHMSerializer):
|
||||
vlan_untagged = VlanSerializer(read_only=True)
|
||||
vlan_tagged = VlanPortSerializer(read_only=True, many=True)
|
||||
|
||||
class Meta:
|
||||
model = topologie.PortProfile
|
||||
fields = ('name', 'profil_default', 'vlan_untagged', 'vlan_tagged', 'radius_type', 'radius_mode', 'speed', 'mac_limit', 'flow_control', 'dhcp_snooping', 'dhcpv6_snooping', 'arp_protect', 'ra_guard', 'loop_protect', 'vlan_untagged', 'vlan_tagged')
|
||||
|
||||
|
||||
class ModelSwitchSerializer(NamespacedHMSerializer):
|
||||
constructor = serializers.CharField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = topologie.ModelSwitch
|
||||
fields = ('reference', 'firmware', 'constructor')
|
||||
|
||||
|
||||
class SwitchBaySerializer(NamespacedHMSerializer):
|
||||
class Meta:
|
||||
model = topologie.SwitchBay
|
||||
fields = ('name',)
|
||||
|
||||
|
||||
class PortsSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Ipv6List` objects.
|
||||
"""
|
||||
get_port_profil = ProfilSerializer(read_only=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = topologie.Port
|
||||
fields = ('state', 'port', 'pretty_name', 'get_port_profil')
|
||||
|
||||
|
||||
|
||||
class SwitchPortSerializer(serializers.ModelSerializer):
|
||||
"""Serialize the data about the switches"""
|
||||
ports = PortsSerializer(many=True, read_only=True)
|
||||
model = ModelSwitchSerializer(read_only=True)
|
||||
switchbay = SwitchBaySerializer(read_only=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = topologie.Switch
|
||||
fields = ('short_name', 'model', 'switchbay', 'ports', 'ipv4', 'ipv6',
|
||||
'interfaces_subnet', 'interfaces6_subnet', 'automatic_provision', 'rest_enabled',
|
||||
'web_management_enabled', 'get_radius_key_value', 'get_management_cred_value')
|
||||
|
||||
# LOCAL EMAILS
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ router.register_viewset(r'machines/service', views.ServiceViewSet)
|
|||
router.register_viewset(r'machines/servicelink', views.ServiceLinkViewSet, base_name='servicelink')
|
||||
router.register_viewset(r'machines/ouvertureportlist', views.OuverturePortListViewSet)
|
||||
router.register_viewset(r'machines/ouvertureport', views.OuverturePortViewSet)
|
||||
router.register_viewset(r'machines/role', views.RoleViewSet)
|
||||
# PREFERENCES
|
||||
router.register_view(r'preferences/optionaluser', views.OptionalUserView),
|
||||
router.register_view(r'preferences/optionalmachine', views.OptionalMachineView),
|
||||
|
@ -81,7 +82,8 @@ router.register_viewset(r'topologie/modelswitch', views.ModelSwitchViewSet)
|
|||
router.register_viewset(r'topologie/constructorswitch', views.ConstructorSwitchViewSet)
|
||||
router.register_viewset(r'topologie/switchbay', views.SwitchBayViewSet)
|
||||
router.register_viewset(r'topologie/building', views.BuildingViewSet)
|
||||
router.register(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport')
|
||||
router.register_viewset(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport')
|
||||
router.register_viewset(r'topologie/portprofile', views.PortProfileViewSet, base_name='portprofile')
|
||||
router.register_viewset(r'topologie/room', views.RoomViewSet)
|
||||
router.register(r'topologie/portprofile', views.PortProfileViewSet)
|
||||
# USERS
|
||||
|
@ -105,6 +107,9 @@ router.register_view(r'localemail/users', views.LocalEmailUsersView),
|
|||
# Firewall
|
||||
router.register_view(r'firewall/subnet-ports', views.SubnetPortsOpenView),
|
||||
router.register_view(r'firewall/interface-ports', views.InterfacePortsOpenView),
|
||||
# Switches config
|
||||
router.register_view(r'switchs/ports-config', views.SwitchPortView),
|
||||
router.register_view(r'switchs/role', views.RoleView),
|
||||
# DNS
|
||||
router.register_view(r'dns/zones', views.DNSZonesView),
|
||||
router.register_view(r'dns/reverse-zones', views.DNSReverseZonesView),
|
||||
|
|
32
api/views.py
32
api/views.py
|
@ -242,6 +242,13 @@ class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
serializer_class = serializers.OuverturePortSerializer
|
||||
|
||||
|
||||
class RoleViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Machine` objects.
|
||||
"""
|
||||
queryset = machines.Role.objects.all()
|
||||
serializer_class = serializers.RoleSerializer
|
||||
|
||||
|
||||
# PREFERENCES
|
||||
# Those views differ a bit because there is only one object
|
||||
# to display, so we don't bother with the listing part
|
||||
|
@ -397,6 +404,13 @@ class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
serializer_class = serializers.SwitchPortSerializer
|
||||
|
||||
|
||||
class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.PortProfile` objects.
|
||||
"""
|
||||
queryset = topologie.PortProfile.objects.all()
|
||||
serializer_class = serializers.PortProfileSerializer
|
||||
|
||||
|
||||
class RoomViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Room` objects.
|
||||
"""
|
||||
|
@ -515,6 +529,24 @@ class ServiceRegenViewSet(viewsets.ModelViewSet):
|
|||
queryset = queryset.filter(server__domain__name__iexact=hostname)
|
||||
return queryset
|
||||
|
||||
# Config des switches
|
||||
|
||||
class SwitchPortView(generics.ListAPIView):
|
||||
"""Exposes the associations between hostname, mac address and IPv4 in
|
||||
order to build the DHCP lease files.
|
||||
"""
|
||||
queryset = topologie.Switch.objects.all().select_related("switchbay").select_related("model__constructor").prefetch_related("ports__custom_profile__vlan_tagged").prefetch_related("ports__custom_profile__vlan_untagged").prefetch_related("ports__machine_interface__domain__extension").prefetch_related("ports__room")
|
||||
|
||||
serializer_class = serializers.SwitchPortSerializer
|
||||
|
||||
|
||||
class RoleView(generics.ListAPIView):
|
||||
"""Exposes the associations between hostname, mac address and IPv4 in
|
||||
order to build the DHCP lease files.
|
||||
"""
|
||||
queryset = machines.Role.objects.all().prefetch_related('servers')
|
||||
serializer_class = serializers.RoleSerializer
|
||||
|
||||
|
||||
# LOCAL EMAILS
|
||||
|
||||
|
|
|
@ -576,13 +576,24 @@ class VlanForm(FormRevMixin, ModelForm):
|
|||
"""Ajout d'un vlan : id, nom"""
|
||||
class Meta:
|
||||
model = Vlan
|
||||
fields = '__all__'
|
||||
fields = ['vlan_id', 'name', 'comment']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
super(VlanForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
|
||||
|
||||
class EditOptionVlanForm(FormRevMixin, ModelForm):
|
||||
"""Ajout d'un vlan : id, nom"""
|
||||
class Meta:
|
||||
model = Vlan
|
||||
fields = ['dhcp_snooping', 'dhcpv6_snooping', 'arp_protect', 'igmp', 'mld']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
super(EditOptionVlanForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
|
||||
|
||||
class DelVlanForm(FormRevMixin, Form):
|
||||
"""Suppression d'un ou plusieurs vlans"""
|
||||
vlan = forms.ModelMultipleChoiceField(
|
||||
|
|
40
machines/migrations/0095_auto_20180919_2225.py
Normal file
40
machines/migrations/0095_auto_20180919_2225.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2018-09-19 20:25
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0094_auto_20180815_1918'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='vlan',
|
||||
name='arp_protect',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vlan',
|
||||
name='dhcp_snooping',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vlan',
|
||||
name='dhcpv6_snooping',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vlan',
|
||||
name='igmp',
|
||||
field=models.BooleanField(default=False, help_text='Gestion multicast v4'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vlan',
|
||||
name='mld',
|
||||
field=models.BooleanField(default=False, help_text='Gestion multicast v6'),
|
||||
),
|
||||
]
|
|
@ -201,6 +201,12 @@ class Machine(RevMixin, FieldPermissionModelMixin, models.Model):
|
|||
de cette machine"""
|
||||
return str(self.interface_set.first().domain.name)
|
||||
|
||||
@cached_property
|
||||
def complete_name(self):
|
||||
"""Par defaut, renvoie le nom de la première interface
|
||||
de cette machine"""
|
||||
return str(self.interface_set.first())
|
||||
|
||||
@cached_property
|
||||
def all_short_names(self):
|
||||
"""Renvoie de manière unique, le nom des interfaces de cette
|
||||
|
@ -515,6 +521,18 @@ class Vlan(RevMixin, AclMixin, models.Model):
|
|||
vlan_id = models.PositiveIntegerField(validators=[MaxValueValidator(4095)])
|
||||
name = models.CharField(max_length=256)
|
||||
comment = models.CharField(max_length=256, blank=True)
|
||||
#Réglages supplémentaires
|
||||
arp_protect = models.BooleanField(default=False)
|
||||
dhcp_snooping = models.BooleanField(default=False)
|
||||
dhcpv6_snooping = models.BooleanField(default=False)
|
||||
igmp = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Gestion multicast v4"
|
||||
)
|
||||
mld = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Gestion multicast v6"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
|
@ -1634,6 +1652,19 @@ class Role(RevMixin, AclMixin, models.Model):
|
|||
machine__interface__role=cls.objects.filter(specific_role=roletype)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, machineid, *_args, **_kwargs):
|
||||
"""Get the Machine instance with machineid.
|
||||
:param userid: The id
|
||||
:return: The user
|
||||
"""
|
||||
return cls.objects.get(pk=machineid)
|
||||
|
||||
@classmethod
|
||||
def interface_for_roletype(cls, roletype):
|
||||
"""Return interfaces for a roletype"""
|
||||
return Interface.objects.filter(role=cls.objects.filter(specific_role=roletype))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(Role, self).save(*args, **kwargs)
|
||||
|
||||
|
|
|
@ -37,7 +37,10 @@ from .models import (
|
|||
MailContact,
|
||||
AssoOption,
|
||||
MailMessageOption,
|
||||
HomeOption
|
||||
HomeOption,
|
||||
RadiusKey,
|
||||
SwitchManagementCred,
|
||||
Reminder
|
||||
)
|
||||
|
||||
|
||||
|
@ -86,6 +89,18 @@ class HomeOptionAdmin(VersionAdmin):
|
|||
pass
|
||||
|
||||
|
||||
class RadiusKeyAdmin(VersionAdmin):
|
||||
"""Class radiuskey"""
|
||||
pass
|
||||
|
||||
class SwitchManagementCredAdmin(VersionAdmin):
|
||||
"""Class managementcred for switch"""
|
||||
pass
|
||||
|
||||
class ReminderAdmin(VersionAdmin):
|
||||
"""Class reminder for switch"""
|
||||
pass
|
||||
|
||||
admin.site.register(OptionalUser, OptionalUserAdmin)
|
||||
admin.site.register(OptionalMachine, OptionalMachineAdmin)
|
||||
admin.site.register(OptionalTopologie, OptionalTopologieAdmin)
|
||||
|
@ -93,5 +108,8 @@ admin.site.register(GeneralOption, GeneralOptionAdmin)
|
|||
admin.site.register(HomeOption, HomeOptionAdmin)
|
||||
admin.site.register(Service, ServiceAdmin)
|
||||
admin.site.register(MailContact, MailContactAdmin)
|
||||
admin.site.register(Reminder, ReminderAdmin)
|
||||
admin.site.register(RadiusKey, RadiusKeyAdmin)
|
||||
admin.site.register(SwitchManagementCred, SwitchManagementCredAdmin)
|
||||
admin.site.register(AssoOption, AssoOptionAdmin)
|
||||
admin.site.register(MailMessageOption, MailMessageOptionAdmin)
|
||||
|
|
|
@ -38,9 +38,12 @@ from .models import (
|
|||
MailMessageOption,
|
||||
HomeOption,
|
||||
Service,
|
||||
MailContact
|
||||
MailContact,
|
||||
Reminder,
|
||||
RadiusKey,
|
||||
SwitchManagementCred,
|
||||
)
|
||||
|
||||
from topologie.models import Switch
|
||||
|
||||
class EditOptionalUserForm(ModelForm):
|
||||
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
|
||||
|
@ -92,7 +95,14 @@ class EditOptionalMachineForm(ModelForm):
|
|||
|
||||
|
||||
class EditOptionalTopologieForm(ModelForm):
|
||||
"""Options de topologie, formulaire d'edition (vlan par default etc)"""
|
||||
"""Options de topologie, formulaire d'edition (vlan par default etc)
|
||||
On rajoute un champ automatic provision switchs pour gérer facilement
|
||||
l'ajout de switchs au provisionning automatique"""
|
||||
automatic_provision_switchs = forms.ModelMultipleChoiceField(
|
||||
Switch.objects.all(),
|
||||
required=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = OptionalTopologie
|
||||
fields = '__all__'
|
||||
|
@ -110,6 +120,14 @@ class EditOptionalTopologieForm(ModelForm):
|
|||
self.fields['vlan_decision_nok'].label = _("VLAN for machines rejected"
|
||||
" by RADIUS")
|
||||
|
||||
self.initial['automatic_provision_switchs'] = Switch.objects.filter(automatic_provision=True)
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = super().save(commit)
|
||||
Switch.objects.all().update(automatic_provision=False)
|
||||
self.cleaned_data['automatic_provision_switchs'].update(automatic_provision=True)
|
||||
return instance
|
||||
|
||||
|
||||
class EditGeneralOptionForm(ModelForm):
|
||||
"""Options générales (affichages de résultats de recherche, etc)"""
|
||||
|
@ -242,8 +260,68 @@ class DelServiceForm(Form):
|
|||
else:
|
||||
self.fields['services'].queryset = Service.objects.all()
|
||||
|
||||
class MailContactForm(FormRevMixin, ModelForm):
|
||||
"""Edit and add contact email adress"""
|
||||
class ReminderForm(FormRevMixin, ModelForm):
|
||||
"""Edition, ajout de services sur la page d'accueil"""
|
||||
class Meta:
|
||||
model = Reminder
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
super(ReminderForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
|
||||
|
||||
class RadiusKeyForm(FormRevMixin, ModelForm):
|
||||
"""Edition, ajout de clef radius"""
|
||||
members = forms.ModelMultipleChoiceField(
|
||||
queryset=Switch.objects.all(),
|
||||
required=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = RadiusKey
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
super(RadiusKeyForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
instance = kwargs.get('instance', None)
|
||||
if instance:
|
||||
self.initial['members'] = Switch.objects.filter(radius_key=instance)
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = super().save(commit)
|
||||
instance.switch_set = self.cleaned_data['members']
|
||||
return instance
|
||||
|
||||
|
||||
class SwitchManagementCredForm(FormRevMixin, ModelForm):
|
||||
"""Edition, ajout de creds de management pour gestion
|
||||
et interface rest des switchs"""
|
||||
members = forms.ModelMultipleChoiceField(
|
||||
Switch.objects.all(),
|
||||
required=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = SwitchManagementCred
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
super(SwitchManagementCredForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
instance = kwargs.get('instance', None)
|
||||
if instance:
|
||||
self.initial['members'] = Switch.objects.filter(management_creds=instance)
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = super().save(commit)
|
||||
instance.switch_set = self.cleaned_data['members']
|
||||
return instance
|
||||
|
||||
|
||||
class MailContactForm(ModelForm):
|
||||
"""Edition, ajout d'adresse de contact"""
|
||||
class Meta:
|
||||
model = MailContact
|
||||
fields = '__all__'
|
||||
|
|
102
preferences/migrations/0051_auto_20180919_2225.py
Normal file
102
preferences/migrations/0051_auto_20180919_2225.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2018-09-19 20:25
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import re2o.aes_field
|
||||
import re2o.mixins
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0095_auto_20180919_2225'),
|
||||
('preferences', '0050_auto_20180818_1329'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='RadiusKey',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('radius_key', re2o.aes_field.AESEncryptedField(help_text='Clef radius', max_length=255)),
|
||||
('comment', models.CharField(blank=True, help_text='Commentaire de cette clef', max_length=255, null=True)),
|
||||
('default_switch', models.BooleanField(default=True, help_text='Clef par défaut des switchs', unique=True)),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_radiuskey', 'Peut voir un objet radiuskey'),),
|
||||
},
|
||||
bases=(re2o.mixins.AclMixin, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Reminder',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('days', models.IntegerField(default=7, help_text="Délais entre le mail et la fin d'adhésion", unique=True)),
|
||||
('message', models.CharField(blank=True, default='', help_text='Message affiché spécifiquement pour ce rappel', max_length=255, null=True)),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_reminder', 'Peut voir un objet reminder'),),
|
||||
},
|
||||
bases=(re2o.mixins.AclMixin, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SwitchManagementCred',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('management_id', models.CharField(help_text='Login du switch', max_length=63)),
|
||||
('management_pass', re2o.aes_field.AESEncryptedField(help_text='Mot de passe', max_length=63)),
|
||||
('default_switch', models.BooleanField(default=True, help_text='Creds par défaut des switchs', unique=True)),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_switchmanagementcred', 'Peut voir un objet switchmanagementcred'),),
|
||||
},
|
||||
bases=(re2o.mixins.AclMixin, models.Model),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='sftp_login',
|
||||
field=models.CharField(blank=True, help_text='Login sftp des switchs', max_length=32, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='sftp_pass',
|
||||
field=re2o.aes_field.AESEncryptedField(blank=True, help_text='Mot de passe sftp', max_length=63, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='switchs_ip_type',
|
||||
field=models.OneToOneField(blank=True, help_text="Plage d'ip de management des switchs", null=True, on_delete=django.db.models.deletion.PROTECT, to='machines.IpType'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='switchs_provision',
|
||||
field=models.CharField(choices=[('sftp', 'sftp'), ('tftp', 'tftp')], default='tftp', help_text='Mode de récupération des confs par les switchs', max_length=32),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='switchs_rest_management',
|
||||
field=models.BooleanField(default=False, help_text='Rest management, activé si provision auto'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='switchs_web_management',
|
||||
field=models.BooleanField(default=False, help_text='Web management, activé si provision automatique'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='optionaltopologie',
|
||||
name='switchs_web_management_ssl',
|
||||
field=models.BooleanField(default=False, help_text='Web management ssl. Assurez-vous que un certif est installé sur le switch !'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='mailmessageoption',
|
||||
name='welcome_mail_en',
|
||||
field=models.TextField(default='', help_text='Mail de bienvenue en anglais'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='mailmessageoption',
|
||||
name='welcome_mail_fr',
|
||||
field=models.TextField(default='', help_text='Mail de bienvenue en français'),
|
||||
),
|
||||
]
|
|
@ -34,7 +34,10 @@ from django.forms import ValidationError
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import machines.models
|
||||
|
||||
from re2o.mixins import AclMixin
|
||||
from re2o.aes_field import AESEncryptedField
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class PreferencesModel(models.Model):
|
||||
|
@ -180,6 +183,10 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
(MACHINE, _("On the IP range's VLAN of the machine")),
|
||||
(DEFINED, _("Preset in 'VLAN for machines accepted by RADIUS'")),
|
||||
)
|
||||
CHOICE_PROVISION = (
|
||||
('sftp', 'sftp'),
|
||||
('tftp', 'tftp'),
|
||||
)
|
||||
|
||||
radius_general_policy = models.CharField(
|
||||
max_length=32,
|
||||
|
@ -200,6 +207,97 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
blank=True,
|
||||
null=True
|
||||
)
|
||||
switchs_web_management = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Web management, activé si provision automatique"
|
||||
)
|
||||
switchs_web_management_ssl = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Web management ssl. Assurez-vous que un certif est installé sur le switch !"
|
||||
)
|
||||
switchs_rest_management = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Rest management, activé si provision auto"
|
||||
)
|
||||
switchs_ip_type = models.OneToOneField(
|
||||
'machines.IpType',
|
||||
on_delete=models.PROTECT,
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text="Plage d'ip de management des switchs"
|
||||
)
|
||||
switchs_provision = models.CharField(
|
||||
max_length=32,
|
||||
choices=CHOICE_PROVISION,
|
||||
default='tftp',
|
||||
help_text="Mode de récupération des confs par les switchs"
|
||||
)
|
||||
sftp_login = models.CharField(
|
||||
max_length=32,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Login sftp des switchs"
|
||||
)
|
||||
sftp_pass = AESEncryptedField(
|
||||
max_length=63,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Mot de passe sftp"
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def provisioned_switchs(self):
|
||||
"""Liste des switches provisionnés"""
|
||||
from topologie.models import Switch
|
||||
return Switch.objects.filter(automatic_provision=True)
|
||||
|
||||
@cached_property
|
||||
def switchs_management_interface(self):
|
||||
"""Return the ip of the interface that the switch have to contact to get it's config"""
|
||||
if self.switchs_ip_type:
|
||||
from machines.models import Role, Interface
|
||||
return Interface.objects.filter(machine__interface__in=Role.interface_for_roletype("switch-conf-server")).filter(type__ip_type=self.switchs_ip_type).first()
|
||||
else:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def switchs_management_interface_ip(self):
|
||||
"""Same, but return the ipv4"""
|
||||
if not self.switchs_management_interface:
|
||||
return None
|
||||
return self.switchs_management_interface.ipv4
|
||||
|
||||
@cached_property
|
||||
def switchs_management_sftp_creds(self):
|
||||
"""Credentials des switchs pour provion sftp"""
|
||||
if self.sftp_login and self.sftp_pass:
|
||||
return {'login' : self.sftp_login, 'pass' : self.sftp_pass}
|
||||
else:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def switchs_management_utils(self):
|
||||
"""Used for switch_conf, return a list of ip on vlans"""
|
||||
from machines.models import Role, Ipv6List, Interface
|
||||
def return_ips_dict(interfaces):
|
||||
return {'ipv4' : [str(interface.ipv4) for interface in interfaces], 'ipv6' : Ipv6List.objects.filter(interface__in=interfaces).values_list('ipv6', flat=True)}
|
||||
|
||||
ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter(type__ip_type=self.switchs_ip_type)
|
||||
log_servers = Role.all_interfaces_for_roletype("log-server").filter(type__ip_type=self.switchs_ip_type)
|
||||
radius_servers = Role.all_interfaces_for_roletype("radius-server").filter(type__ip_type=self.switchs_ip_type)
|
||||
dhcp_servers = Role.all_interfaces_for_roletype("dhcp-server")
|
||||
subnet = None
|
||||
subnet6 = None
|
||||
if self.switchs_ip_type:
|
||||
subnet = self.switchs_ip_type.ip_set_full_info
|
||||
subnet6 = self.switchs_ip_type.ip6_set_full_info
|
||||
return {'ntp_servers': return_ips_dict(ntp_servers), 'log_servers': return_ips_dict(log_servers), 'radius_servers': return_ips_dict(radius_servers), 'dhcp_servers': return_ips_dict(dhcp_servers), 'subnet': subnet, 'subnet6': subnet6}
|
||||
|
||||
@cached_property
|
||||
def provision_switchs_enabled(self):
|
||||
"""Return true if all settings are ok : switchs on automatic provision,
|
||||
ip_type"""
|
||||
return bool(self.provisioned_switchs and self.switchs_ip_type and SwitchManagementCred.objects.filter(default_switch=True).exists() and self.switchs_management_interface_ip and bool(self.switchs_provision != 'sftp' or self.switchs_management_sftp_creds))
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
|
@ -215,6 +313,91 @@ def optionaltopologie_post_save(**kwargs):
|
|||
topologie_pref.set_in_cache()
|
||||
|
||||
|
||||
class RadiusKey(AclMixin, models.Model):
|
||||
"""Class of a radius key"""
|
||||
radius_key = AESEncryptedField(
|
||||
max_length=255,
|
||||
help_text="Clef radius"
|
||||
)
|
||||
comment = models.CharField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Commentaire de cette clef"
|
||||
)
|
||||
default_switch = models.BooleanField(
|
||||
default=True,
|
||||
unique=True,
|
||||
help_text= "Clef par défaut des switchs"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("view_radiuskey", "Peut voir un objet radiuskey"),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Clef radius " + str(self.id) + " " + str(self.comment)
|
||||
|
||||
|
||||
class SwitchManagementCred(AclMixin, models.Model):
|
||||
"""Class of a management creds of a switch, for rest management"""
|
||||
management_id = models.CharField(
|
||||
max_length=63,
|
||||
help_text="Login du switch"
|
||||
)
|
||||
management_pass = AESEncryptedField(
|
||||
max_length=63,
|
||||
help_text="Mot de passe"
|
||||
)
|
||||
default_switch = models.BooleanField(
|
||||
default=True,
|
||||
unique=True,
|
||||
help_text= "Creds par défaut des switchs"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("view_switchmanagementcred", "Peut voir un objet switchmanagementcred"),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Identifiant " + str(self.management_id)
|
||||
|
||||
|
||||
class Reminder(AclMixin, models.Model):
|
||||
"""Options pour les mails de notification de fin d'adhésion.
|
||||
Days: liste des nombres de jours pour lesquells un mail est envoyé
|
||||
optionalMessage: message additionel pour le mail
|
||||
"""
|
||||
PRETTY_NAME="Options pour le mail de fin d'adhésion"
|
||||
|
||||
days = models.IntegerField(
|
||||
default=7,
|
||||
unique=True,
|
||||
help_text="Délais entre le mail et la fin d'adhésion"
|
||||
)
|
||||
message = models.CharField(
|
||||
max_length=255,
|
||||
default="",
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Message affiché spécifiquement pour ce rappel"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("view_reminder", "Peut voir un objet reminder"),
|
||||
)
|
||||
|
||||
def users_to_remind(self):
|
||||
from re2o.utils import all_has_access
|
||||
date = timezone.now().replace(minute=0,hour=0)
|
||||
futur_date = date + timedelta(days=self.days)
|
||||
users = all_has_access(futur_date).exclude(pk__in = all_has_access(futur_date + timedelta(days=1)))
|
||||
return users
|
||||
|
||||
|
||||
class GeneralOption(AclMixin, PreferencesModel):
|
||||
"""Options générales : nombre de resultats par page, nom du site,
|
||||
temps où les liens sont valides"""
|
||||
|
@ -383,8 +566,8 @@ def homeoption_post_save(**kwargs):
|
|||
class MailMessageOption(AclMixin, models.Model):
|
||||
"""Reglages, mail de bienvenue et autre"""
|
||||
|
||||
welcome_mail_fr = models.TextField(default="")
|
||||
welcome_mail_en = models.TextField(default="")
|
||||
welcome_mail_fr = models.TextField(default="", help_text="Mail de bienvenue en français")
|
||||
welcome_mail_en = models.TextField(default="", help_text="Mail de bienvenue en anglais")
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
|
|
57
preferences/templates/preferences/aff_radiuskey.html
Normal file
57
preferences/templates/preferences/aff_radiuskey.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
{% comment %}
|
||||
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||
se veut agnostique au réseau considéré, de manière à être installable en
|
||||
quelques clics.
|
||||
|
||||
Copyright © 2017 Gabriel Détraz
|
||||
Copyright © 2017 Goulven Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
{% endcomment %}
|
||||
{% load acl %}
|
||||
{% load logs_extra %}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id Clef</th>
|
||||
<th>Commentaire</th>
|
||||
<th>Clef par default des switchs</th>
|
||||
<th>Clef utilisée par les switchs</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for radiuskey in radiuskey_list %}
|
||||
<tr>
|
||||
<td>{{ radiuskey.id }}</td>
|
||||
<td>{{ radiuskey.comment }}</td>
|
||||
<td>{{ radiuskey.default_switch }}</td>
|
||||
<td>{{ radiuskey.switch_set.all|join:", " }}</td>
|
||||
<td class="text-right">
|
||||
{% can_edit radiuskey %}
|
||||
{% include 'buttons/edit.html' with href='preferences:edit-radiuskey' id=radiuskey.id %}
|
||||
{% acl_end %}
|
||||
{% can_delete radiuskey %}
|
||||
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'preferences:del-radiuskey' radiuskey.pk %}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
{% history_button radiuskey %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
{% comment %}
|
||||
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||
se veut agnostique au réseau considéré, de manière à être installable en
|
||||
quelques clics.
|
||||
|
||||
Copyright © 2017 Gabriel Détraz
|
||||
Copyright © 2017 Goulven Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
{% endcomment %}
|
||||
{% load acl %}
|
||||
{% load logs_extra %}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Identifiant</th>
|
||||
<th>Creds par default des switchs</th>
|
||||
<th>Utilisé pour les switchs</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for switchmanagementcred in switchmanagementcred_list %}
|
||||
<tr>
|
||||
<td>{{ switchmanagementcred.management_id }}</td>
|
||||
<td>{{ switchmanagementcred.default_switch }}</td>
|
||||
<td>{{ switchmanagementcred.switch_set.all|join:", " }}</td>
|
||||
<td class="text-right">
|
||||
{% can_edit switchmanagementcred %}
|
||||
{% include 'buttons/edit.html' with href='preferences:edit-switchmanagementcred' id=switchmanagementcred.id %}
|
||||
{% acl_end %}
|
||||
{% can_delete switchmanagementcred %}
|
||||
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'preferences:del-switchmanagementcred' switchmanagementcred.pk %}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
{% acl_end %}
|
||||
{% history_button switchmanagementcred %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
40
preferences/templates/preferences/delete.html
Normal file
40
preferences/templates/preferences/delete.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
{% extends "topologie/sidebar.html" %}
|
||||
{% comment %}
|
||||
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||
se veut agnostique au réseau considéré, de manière à être installable en
|
||||
quelques clics.
|
||||
|
||||
Copyright © 2017 Gabriel Détraz
|
||||
Copyright © 2017 Goulven Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
{% endcomment %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Création et modification de machines{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
<h4>Attention, voulez-vous vraiment supprimer cet objet {{ objet_name }} ( {{ objet }} ) ?</h4>
|
||||
{% bootstrap_button "Confirmer" button_type="submit" icon="trash" %}
|
||||
</form>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
|
@ -118,6 +118,75 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<th>{% trans "VLAN for machines rejected by RADIUS" %}</th>
|
||||
<td>{{ topologieoptions.vlan_decision_nok }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Placement sur ce vlan par default en cas de rejet</th>
|
||||
<td>{{ topologieoptions.vlan_decision_nok }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h6>Clef radius</h6>
|
||||
{% can_create RadiusKey%}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-radiuskey' %}"><i class="fa fa-plus"></i> Ajouter une clef radius</a>
|
||||
{% acl_end %}
|
||||
{% include "preferences/aff_radiuskey.html" with radiuskey_list=radiuskey_list %}
|
||||
|
||||
<h4>Configuration des switches</h4>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Web management, activé si provision automatique</th>
|
||||
<td>{{ topologieoptions.switchs_web_management }}</td>
|
||||
<th>Rest management, activé si provision auto</th>
|
||||
<td>{{ topologieoptions.switchs_rest_management }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<h5>{% if topologieoptions.provision_switchs_enabled %}<span class="label label-success">Provision de la config des switchs{% else %}<span class="label label-danger">Provision de la config des switchs{% endif%}</span></h5>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Switchs configurés automatiquement</th>
|
||||
<td>{{ topologieoptions.provisioned_switchs|join:", " }} {% if topologieoptions.provisioned_switchs %}<span class="label label-success"> OK{% else %}<span class="label label-danger">Manquant{% endif %}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Plage d'ip de management des switchs</th>
|
||||
<td>{{ topologieoptions.switchs_ip_type }} {% if topologieoptions.switchs_ip_type %}<span class="label label-success"> OK{% else %}<span class="label label-danger">Manquant{% endif %}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Serveur des config des switchs</th>
|
||||
<td>{{ topologieoptions.switchs_management_interface }} {% if topologieoptions.switchs_management_interface %} - {{ topologieoptions.switchs_management_interface_ip }} <span class="label label-success"> OK{% else %}<span class="label label-danger">Manquant{% endif %}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Mode de provision des switchs</th>
|
||||
<td>{{ topologieoptions.switchs_provision }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Mode TFTP</th>
|
||||
<td><span class="label label-success"> OK</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Mode SFTP</th>
|
||||
<td>{% if topologieoptions.switchs_management_sftp_creds %}<span class="label label-success"> OK{% else %}<span class="label label-danger">Creds manquants{% endif %}</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h6>Creds de management des switchs</h6>
|
||||
{% can_create SwitchManagementCred%}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:add-switchmanagementcred' %}"><i class="fa fa-plus"></i> Ajouter un id/mdp de management switch</a>
|
||||
{% acl_end %}
|
||||
<p>
|
||||
</p>
|
||||
{% if switchmanagementcred_list %}<span class="label label-success"> OK{% else %}<span class="label label-danger">Manquant{% endif %}</span>
|
||||
{% include "preferences/aff_switchmanagementcred.html" with switchmanagementcred_list=switchmanagementcred_list %}
|
||||
|
||||
|
||||
|
||||
<h5>{% if topologieoptions.provisioned_switchs %}<span class="label label-success">Provision de la config des switchs{% else %}<span class="label label-danger">Provision de la config des switchs{% endif%}</span></h5>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Switchs configurés automatiquement</th>
|
||||
<td>{{ topologieoptions.provisioned_switchs|join:", " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h4>{% trans "General preferences" %}</h4>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'preferences:edit-options' 'GeneralOption' %}">
|
||||
|
|
|
@ -36,7 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
<form class="form" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% massive_bootstrap_form options 'utilisateur_asso' %}
|
||||
{% massive_bootstrap_form options 'utilisateur_asso,automatic_provision_switchs' %}
|
||||
{% trans "Edit" as tr_edit %}
|
||||
{% bootstrap_button tr_edit button_type="submit" icon='ok' button_class='btn-success' %}
|
||||
</form>
|
||||
|
|
|
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
{% load massive_bootstrap_form %}
|
||||
|
||||
{% block title %}{% trans "Preferences" %}{% endblock %}
|
||||
|
||||
|
@ -37,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<form class="form" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% if preferenceform %}
|
||||
{% bootstrap_form preferenceform %}
|
||||
{% massive_bootstrap_form preferenceform 'members' %}
|
||||
{% endif %}
|
||||
{% bootstrap_button action_name button_type="submit" icon='ok' button_class='btn-success' %}
|
||||
</form>
|
||||
|
|
|
@ -80,5 +80,26 @@ urlpatterns = [
|
|||
name='edit-mailcontact'
|
||||
),
|
||||
url(r'^del_mailcontact/$', views.del_mailcontact, name='del-mailcontact'),
|
||||
url(r'^add_reminder/$', views.add_reminder, name='add-reminder'),
|
||||
url(
|
||||
r'^edit_reminder/(?P<reminderid>[0-9]+)$',
|
||||
views.edit_reminder,
|
||||
name='edit-reminder'
|
||||
),
|
||||
url(r'^del_reminder/$', views.del_reminder, name='del-reminder'),
|
||||
url(r'^add_radiuskey/$', views.add_radiuskey, name='add-radiuskey'),
|
||||
url(
|
||||
r'^edit_radiuskey/(?P<radiuskeyid>[0-9]+)$',
|
||||
views.edit_radiuskey,
|
||||
name='edit-radiuskey'
|
||||
),
|
||||
url(r'^del_radiuskey/(?P<radiuskeyid>[0-9]+)$', views.del_radiuskey, name='del-radiuskey'),
|
||||
url(r'^add_switchmanagementcred/$', views.add_switchmanagementcred, name='add-switchmanagementcred'),
|
||||
url(
|
||||
r'^edit_switchmanagementcred/(?P<switchmanagementcredid>[0-9]+)$',
|
||||
views.edit_switchmanagementcred,
|
||||
name='edit-switchmanagementcred'
|
||||
),
|
||||
url(r'^del_switchmanagementcred/(?P<switchmanagementcredid>[0-9]+)$', views.del_switchmanagementcred, name='del-switchmanagementcred'),
|
||||
url(r'^$', views.display_options, name='display-options'),
|
||||
]
|
||||
|
|
|
@ -41,10 +41,14 @@ from django.utils.translation import ugettext as _
|
|||
from reversion import revisions as reversion
|
||||
|
||||
from re2o.views import form
|
||||
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all
|
||||
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all, can_delete
|
||||
|
||||
from .forms import MailContactForm, DelMailContactForm
|
||||
from .forms import (
|
||||
ServiceForm, DelServiceForm, MailContactForm, DelMailContactForm
|
||||
ServiceForm,
|
||||
ReminderForm,
|
||||
RadiusKeyForm,
|
||||
SwitchManagementCredForm
|
||||
)
|
||||
from .models import (
|
||||
Service,
|
||||
|
@ -55,7 +59,10 @@ from .models import (
|
|||
MailMessageOption,
|
||||
GeneralOption,
|
||||
OptionalTopologie,
|
||||
HomeOption
|
||||
HomeOption,
|
||||
Reminder,
|
||||
RadiusKey,
|
||||
SwitchManagementCred
|
||||
)
|
||||
from . import models
|
||||
from . import forms
|
||||
|
@ -76,6 +83,9 @@ def display_options(request):
|
|||
mailmessageoptions, _created = MailMessageOption.objects.get_or_create()
|
||||
service_list = Service.objects.all()
|
||||
mailcontact_list = MailContact.objects.all()
|
||||
reminder_list = Reminder.objects.all()
|
||||
radiuskey_list = RadiusKey.objects.all()
|
||||
switchmanagementcred_list = SwitchManagementCred.objects.all()
|
||||
return form({
|
||||
'useroptions': useroptions,
|
||||
'machineoptions': machineoptions,
|
||||
|
@ -85,7 +95,10 @@ def display_options(request):
|
|||
'homeoptions': homeoptions,
|
||||
'mailmessageoptions': mailmessageoptions,
|
||||
'service_list': service_list,
|
||||
'mailcontact_list': mailcontact_list
|
||||
'mailcontact_list': mailcontact_list,
|
||||
'reminder_list': reminder_list,
|
||||
'radiuskey_list' : radiuskey_list,
|
||||
'switchmanagementcred_list': switchmanagementcred_list,
|
||||
}, 'preferences/display_preferences.html', request)
|
||||
|
||||
|
||||
|
@ -196,6 +209,164 @@ def del_service(request, instances):
|
|||
request
|
||||
)
|
||||
|
||||
@login_required
|
||||
@can_create(Reminder)
|
||||
def add_reminder(request):
|
||||
"""Ajout d'un service de la page d'accueil"""
|
||||
reminder = ReminderForm(request.POST or None, request.FILES or None)
|
||||
if service.is_valid():
|
||||
with transaction.atomic(), reversion.create_revision():
|
||||
reminder.save()
|
||||
reversion.set_user(request.user)
|
||||
reversion.set_comment("Creation")
|
||||
messages.success(request, _("The service was added."))
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'preferenceform': service, 'action_name': _("Add a service")},
|
||||
'preferences/preferences.html',
|
||||
request
|
||||
)
|
||||
|
||||
@login_required
|
||||
@can_edit(Reminder)
|
||||
def edit_reminder(request, service_instance, **_kwargs):
|
||||
"""Edition des services affichés sur la page d'accueil"""
|
||||
reminder = ReminderForm(
|
||||
request.POST or None,
|
||||
request.FILES or None,
|
||||
instance=reminder_instance
|
||||
)
|
||||
if reminder.is_valid():
|
||||
with transaction.atomic(), reversion.create_revision():
|
||||
reminder.save()
|
||||
reversion.set_user(request.user)
|
||||
reversion.set_comment(
|
||||
"Field(s) edited: %s" % ', '.join(
|
||||
field for field in reminder.changed_data
|
||||
)
|
||||
)
|
||||
messages.success(request, _("The service was edited."))
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'preferenceform': service, 'action_name': _("Edit")},
|
||||
'preferences/preferences.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@can_delete(Reminder)
|
||||
def del_reminder(request, reminder_instance, **_kwargs):
|
||||
"""Destruction d'un reminder"""
|
||||
if request.method == "POST":
|
||||
reminder_instance.delete()
|
||||
messages.success(request, "Le reminder a été détruit")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'objet': reminder_instance, 'objet_name': 'reminder'},
|
||||
'preferences/delete.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_create(RadiusKey)
|
||||
def add_radiuskey(request):
|
||||
"""Ajout d'une clef radius"""
|
||||
radiuskey = RadiusKeyForm(request.POST or None)
|
||||
if radiuskey.is_valid():
|
||||
radiuskey.save()
|
||||
messages.success(request, "Cette clef a été ajouté")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'preferenceform': radiuskey, 'action_name': 'Ajouter'},
|
||||
'preferences/preferences.html',
|
||||
request
|
||||
)
|
||||
|
||||
@can_edit(RadiusKey)
|
||||
def edit_radiuskey(request, radiuskey_instance, **_kwargs):
|
||||
"""Edition des clefs radius"""
|
||||
radiuskey = RadiusKeyForm(request.POST or None, instance=radiuskey_instance)
|
||||
if radiuskey.is_valid():
|
||||
radiuskey.save()
|
||||
messages.success(request, "Radiuskey modifié")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'preferenceform': radiuskey, 'action_name': 'Editer'},
|
||||
'preferences/preferences.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_delete(RadiusKey)
|
||||
def del_radiuskey(request, radiuskey_instance, **_kwargs):
|
||||
"""Destruction d'un radiuskey"""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
radiuskey_instance.delete()
|
||||
messages.success(request, "La radiuskey a été détruite")
|
||||
except ProtectedError:
|
||||
messages.error(request, "Erreur la\
|
||||
clef ne peut être supprimé, elle est affectée à des switchs")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'objet': radiuskey_instance, 'objet_name': 'radiuskey'},
|
||||
'preferences/delete.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_create(SwitchManagementCred)
|
||||
def add_switchmanagementcred(request):
|
||||
"""Ajout de creds de management"""
|
||||
switchmanagementcred = SwitchManagementCredForm(request.POST or None)
|
||||
if switchmanagementcred.is_valid():
|
||||
switchmanagementcred.save()
|
||||
messages.success(request, "Ces creds ont été ajoutés")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'preferenceform': switchmanagementcred, 'action_name': 'Ajouter'},
|
||||
'preferences/preferences.html',
|
||||
request
|
||||
)
|
||||
|
||||
@can_edit(SwitchManagementCred)
|
||||
def edit_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
|
||||
"""Edition des creds de management"""
|
||||
switchmanagementcred = SwitchManagementCredForm(request.POST or None, instance=switchmanagementcred_instance)
|
||||
if switchmanagementcred.is_valid():
|
||||
switchmanagementcred.save()
|
||||
messages.success(request, "Creds de managament modifié")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'preferenceform': switchmanagementcred, 'action_name': 'Editer'},
|
||||
'preferences/preferences.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_delete(SwitchManagementCred)
|
||||
def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
|
||||
"""Destruction d'un switchmanagementcred"""
|
||||
if request.method == "POST":
|
||||
try:
|
||||
switchmanagementcred_instance.delete()
|
||||
messages.success(request, "Ces creds ont été détruits")
|
||||
except ProtectedError:
|
||||
messages.error(request, "Erreur ces\
|
||||
creds ne peuvent être supprimés, ils sont affectés à des switchs")
|
||||
return redirect(reverse('preferences:display-options'))
|
||||
return form(
|
||||
{'objet': switchmanagementcred_instance, 'objet_name': 'switchmanagementcred'},
|
||||
'preferences/delete.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_create(MailContact)
|
||||
|
|
32
topologie/migrations/0063_auto_20180919_2225.py
Normal file
32
topologie/migrations/0063_auto_20180919_2225.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2018-09-19 20:25
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('preferences', '0051_auto_20180919_2225'),
|
||||
('topologie', '0062_auto_20180815_1918'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='modelswitch',
|
||||
name='firmware',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='switch',
|
||||
name='management_creds',
|
||||
field=models.ForeignKey(blank=True, help_text='Identifiant de management de ce switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.SwitchManagementCred'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='switch',
|
||||
name='radius_key',
|
||||
field=models.ForeignKey(blank=True, help_text='Clef radius du switch', null=True, on_delete=django.db.models.deletion.PROTECT, to='preferences.RadiusKey'),
|
||||
),
|
||||
]
|
20
topologie/migrations/0064_switch_automatic_provision.py
Normal file
20
topologie/migrations/0064_switch_automatic_provision.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2018-09-20 16:28
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('topologie', '0063_auto_20180919_2225'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='switch',
|
||||
name='automatic_provision',
|
||||
field=models.BooleanField(default=False, help_text='Provision automatique de ce switch'),
|
||||
),
|
||||
]
|
|
@ -49,6 +49,11 @@ from django.db import transaction
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from reversion import revisions as reversion
|
||||
|
||||
from preferences.models import (
|
||||
OptionalTopologie,
|
||||
RadiusKey,
|
||||
SwitchManagementCred
|
||||
)
|
||||
from machines.models import Machine, regen
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
|
||||
|
@ -228,6 +233,24 @@ class Switch(AclMixin, Machine):
|
|||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
radius_key = models.ForeignKey(
|
||||
'preferences.RadiusKey',
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=models.PROTECT,
|
||||
help_text="Clef radius du switch"
|
||||
)
|
||||
management_creds = models.ForeignKey(
|
||||
'preferences.SwitchManagementCred',
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=models.PROTECT,
|
||||
help_text="Identifiant de management de ce switch"
|
||||
)
|
||||
automatic_provision = models.BooleanField(
|
||||
default=False,
|
||||
help_text='Provision automatique de ce switch',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('stack', 'stack_member_id')
|
||||
|
@ -285,13 +308,78 @@ class Switch(AclMixin, Machine):
|
|||
ValidationError(_("Creation of an existing port."))
|
||||
|
||||
def main_interface(self):
|
||||
""" Returns the 'main' interface of the switch """
|
||||
""" Returns the 'main' interface of the switch
|
||||
It must the the management interface for that device"""
|
||||
switch_iptype = OptionalTopologie.get_cached_value('switchs_ip_type')
|
||||
if switch_iptype:
|
||||
return self.interface_set.filter(type__ip_type=switch_iptype).first()
|
||||
return self.interface_set.first()
|
||||
|
||||
@cached_property
|
||||
def get_name(self):
|
||||
return self.name or self.main_interface().domain.name
|
||||
|
||||
@cached_property
|
||||
def get_radius_key(self):
|
||||
"""Retourne l'objet de la clef radius de ce switch"""
|
||||
return self.radius_key or RadiusKey.objects.filter(default_switch=True).first()
|
||||
|
||||
@cached_property
|
||||
def get_radius_key_value(self):
|
||||
"""Retourne la valeur en str de la clef radius, none si il n'y en a pas"""
|
||||
if self.get_radius_key:
|
||||
return self.get_radius_key.radius_key
|
||||
else:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def get_management_cred(self):
|
||||
"""Retourne l'objet des creds de managament de ce switch"""
|
||||
return self.management_creds or SwitchManagementCred.objects.filter(default_switch=True).first()
|
||||
|
||||
@cached_property
|
||||
def get_management_cred_value(self):
|
||||
"""Retourne un dict des creds de management du switch"""
|
||||
if self.get_management_cred:
|
||||
return {'id': self.get_management_cred.management_id, 'pass': self.get_management_cred.management_pass}
|
||||
else:
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def rest_enabled(self):
|
||||
return OptionalTopologie.get_cached_value('switchs_rest_management') or self.automatic_provision
|
||||
|
||||
@cached_property
|
||||
def web_management_enabled(self):
|
||||
sw_management = OptionalTopologie.get_cached_value('switchs_web_management')
|
||||
sw_management_ssl = OptionalTopologie.get_cached_value('switchs_web_management_ssl')
|
||||
if sw_management_ssl:
|
||||
return "ssl"
|
||||
elif sw_management:
|
||||
return "plain"
|
||||
else:
|
||||
return self.automatic_provision
|
||||
|
||||
@cached_property
|
||||
def ipv4(self):
|
||||
"""Return the switch's management ipv4"""
|
||||
return str(self.main_interface().ipv4)
|
||||
|
||||
@cached_property
|
||||
def ipv6(self):
|
||||
"""Returne the switch's management ipv6"""
|
||||
return str(self.main_interface().ipv6().first())
|
||||
|
||||
@cached_property
|
||||
def interfaces_subnet(self):
|
||||
"""Return dict ip:subnet for all ip of the switch"""
|
||||
return dict((str(interface.ipv4), interface.type.ip_type.ip_set_full_info) for interface in self.interface_set.all())
|
||||
|
||||
@cached_property
|
||||
def interfaces6_subnet(self):
|
||||
"""Return dict ip6:subnet for all ipv6 of the switch"""
|
||||
return dict((str(interface.ipv6().first()), interface.type.ip_type.ip6_set_full_info) for interface in self.interface_set.all())
|
||||
|
||||
def __str__(self):
|
||||
return str(self.get_name)
|
||||
|
||||
|
@ -304,6 +392,11 @@ class ModelSwitch(AclMixin, RevMixin, models.Model):
|
|||
'topologie.ConstructorSwitch',
|
||||
on_delete=models.PROTECT
|
||||
)
|
||||
firmware = models.CharField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
|
@ -437,8 +530,20 @@ class Port(AclMixin, RevMixin, models.Model):
|
|||
verbose_name_plural = _("ports")
|
||||
|
||||
@cached_property
|
||||
def get_port_profile(self):
|
||||
"""Return the config profile for this port
|
||||
def pretty_name(self):
|
||||
"""More elaborated name for label on switch conf"""
|
||||
if self.related:
|
||||
return "Uplink : " + self.related.switch.short_name
|
||||
elif self.machine_interface:
|
||||
return "Machine : " + str(self.machine_interface.domain)
|
||||
elif self.room:
|
||||
return "Chambre : " + str(self.room)
|
||||
else:
|
||||
return "Inconnue"
|
||||
|
||||
@cached_property
|
||||
def get_port_profil(self):
|
||||
"""Return the config profil for this port
|
||||
:returns: the profile of self (port)"""
|
||||
def profile_or_nothing(profile):
|
||||
port_profile = PortProfile.objects.filter(
|
||||
|
@ -447,7 +552,7 @@ class Port(AclMixin, RevMixin, models.Model):
|
|||
return port_profile
|
||||
else:
|
||||
nothing_profile, _created = PortProfile.objects.get_or_create(
|
||||
profile_default='nothing',
|
||||
profil_default='nothing',
|
||||
name='nothing',
|
||||
radius_type='NO'
|
||||
)
|
||||
|
|
|
@ -35,15 +35,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<tr>
|
||||
{% trans "Reference" as tr_ref %}
|
||||
<th>{% include "buttons/sort.html" with prefix='model-switch' col='reference' text=tr_ref %}</th>
|
||||
<th>Firmware</th>
|
||||
{% trans "Switch constructor" as tr_constructor %}
|
||||
<th>{% include "buttons/sort.html" with prefix='model-switch' col='constructor' text=tr_constructor %}</th>
|
||||
<th></th>
|
||||
<th>{% trans "Switches" %}
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for model_switch in model_switch_list %}
|
||||
<tr>
|
||||
<td>{{ model_switch.reference }}</td>
|
||||
<td>{{model_switch.firmware}}</td>
|
||||
<td>{{ model_switch.constructor }}</td>
|
||||
<td>
|
||||
{% for switch in model_switch.switch_set.all %}
|
||||
<a href="{% url 'topologie:index-port' switch.pk %}">
|
||||
{{ switch }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{% can_edit model_switch %}
|
||||
<a class="btn btn-primary btn-sm" role="button" title={% trans "Edit" %} href="{% url 'topologie:edit-model-switch' model_switch.id %}">
|
||||
|
@ -64,4 +74,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
{% if model_switch_list.paginator %}
|
||||
{% include "pagination.html" with list=model_switch_list %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
|
60
topologie/templates/topologie/aff_vlanoptions.html
Normal file
60
topologie/templates/topologie/aff_vlanoptions.html
Normal file
|
@ -0,0 +1,60 @@
|
|||
{% comment %}
|
||||
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||
se veut agnostique au réseau considéré, de manière à être installable en
|
||||
quelques clics.
|
||||
|
||||
Copyright © 2017 Gabriel Détraz
|
||||
Copyright © 2017 Goulven Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
{% endcomment %}
|
||||
|
||||
{% load acl %}
|
||||
{% load logs_extra %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Nom</th>
|
||||
<th>Arp Protect</th>
|
||||
<th>Dhcp Snooping</th>
|
||||
<th>Dhcpv6 Snooping</th>
|
||||
<th>Igmp</th>
|
||||
<th>Mld</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for vlan in vlan_list %}
|
||||
<tr>
|
||||
<td>{{ vlan.vlan_id }}</td>
|
||||
<td>{{ vlan.name }}</td>
|
||||
<td>{{ vlan.arp_protect }}</td>
|
||||
<td>{{ vlan.dhcp_snooping }}</td>
|
||||
<td>{{ vlan.dhcpv6_snooping }}</td>
|
||||
<td>{{ vlan.igmp }}</td>
|
||||
<td>{{ vlan.mld }}</td>
|
||||
<td class="text-right">
|
||||
{% can_edit vlan %}
|
||||
{% include 'buttons/edit.html' with href='topologie:edit-vlanoptions' id=vlan.id %}
|
||||
{% acl_end %}
|
||||
{% history_button vlan %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
|
@ -30,12 +30,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
{% block content %}
|
||||
|
||||
|
||||
<h2>{% trans "Port profiles" %}</h2>
|
||||
{% can_create PortProfile %}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:new-port-profile' %}"><i class="fa fa-plus"></i>{% trans " Add a port profile" %}</a>
|
||||
<hr>
|
||||
{% acl_end %}
|
||||
{% include "topologie/aff_port_profile.html" with port_profile_list=port_profile_list %}
|
||||
|
||||
|
||||
<h2>{% trans "Sécurité par vlan" %}</h2>
|
||||
{% include "topologie/aff_vlanoptions.html" with vlan_list=vlan_list %}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
|
|
@ -120,4 +120,7 @@ urlpatterns = [
|
|||
url(r'^del_port_profile/(?P<portprofileid>[0-9]+)$',
|
||||
views.del_port_profile,
|
||||
name='del-port-profile'),
|
||||
]
|
||||
url(r'^edit_vlanoptions/(?P<vlanid>[0-9]+)$',
|
||||
views.edit_vlanoptions,
|
||||
name='edit-vlanoptions'),
|
||||
]
|
||||
|
|
|
@ -60,10 +60,15 @@ from re2o.settings import MEDIA_ROOT
|
|||
from machines.forms import (
|
||||
DomainForm,
|
||||
EditInterfaceForm,
|
||||
AddInterfaceForm
|
||||
AddInterfaceForm,
|
||||
EditOptionVlanForm
|
||||
)
|
||||
from machines.views import generate_ipv4_mbf_param
|
||||
from machines.models import Interface, Service_link
|
||||
from machines.models import (
|
||||
Interface,
|
||||
Service_link,
|
||||
Vlan
|
||||
)
|
||||
from preferences.models import AssoOption, GeneralOption
|
||||
|
||||
from .models import (
|
||||
|
@ -153,10 +158,11 @@ def index_port_profile(request):
|
|||
'vlan_untagged')
|
||||
port_profile_list = re2o_paginator(
|
||||
request, port_profile_list, pagination_number)
|
||||
vlan_list = Vlan.objects.all().order_by('vlan_id')
|
||||
return render(
|
||||
request,
|
||||
'topologie/index_portprofile.html',
|
||||
{'port_profile_list': port_profile_list}
|
||||
{'port_profile_list': port_profile_list, 'vlan_list': vlan_list}
|
||||
)
|
||||
|
||||
|
||||
|
@ -307,6 +313,23 @@ def index_model_switch(request):
|
|||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_edit(Vlan)
|
||||
def edit_vlanoptions(request, vlan_instance, **_kwargs):
|
||||
""" View used to edit options for switch of VLAN object """
|
||||
vlan = EditOptionVlanForm(request.POST or None, instance=vlan_instance)
|
||||
if vlan.is_valid():
|
||||
if vlan.changed_data:
|
||||
vlan.save()
|
||||
messages.success(request, "Vlan modifié")
|
||||
return redirect(reverse('topologie:index-port-profile'))
|
||||
return form(
|
||||
{'vlanform': vlan, 'action_name': 'Editer'},
|
||||
'machines/machine.html',
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@can_create(Port)
|
||||
def new_port(request, switchid):
|
||||
|
|
Loading…
Reference in a new issue