8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-23 15:33:45 +00:00

Gestion des switchs à provisioner automatiquement

This commit is contained in:
Gabriel Detraz 2018-07-09 21:05:50 +02:00
parent e7f301c392
commit d1131d732f
12 changed files with 377 additions and 10 deletions

View file

@ -40,6 +40,7 @@ from .models import (
MailContact, MailContact,
Reminder Reminder
) )
from topologie.models import Switch
class EditOptionalUserForm(ModelForm): class EditOptionalUserForm(ModelForm):
"""Formulaire d'édition des options de l'user. (solde, telephone..)""" """Formulaire d'édition des options de l'user. (solde, telephone..)"""
@ -77,7 +78,14 @@ class EditOptionalMachineForm(ModelForm):
class EditOptionalTopologieForm(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: class Meta:
model = OptionalTopologie model = OptionalTopologie
fields = '__all__' fields = '__all__'
@ -94,6 +102,14 @@ class EditOptionalTopologieForm(ModelForm):
self.fields['vlan_decision_nok'].label = "Vlan où placer les\ self.fields['vlan_decision_nok'].label = "Vlan où placer les\
machines après rejet RADIUS" machines après rejet 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): class EditGeneralOptionForm(ModelForm):
"""Options générales (affichages de résultats de recherche, etc)""" """Options générales (affichages de résultats de recherche, etc)"""

View file

@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-03 05:43
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import preferences.aes_field
class Migration(migrations.Migration):
dependencies = [
('preferences', '0039_merge_20180701_1852'),
]
operations = [
migrations.AlterField(
model_name='assooption',
name='adresse1',
field=models.CharField(default='1 Rue de exemple', help_text='Adresse', max_length=128),
),
migrations.AlterField(
model_name='assooption',
name='contact',
field=models.EmailField(default='contact@example.org', help_text='Mail de contact', max_length=254),
),
migrations.AlterField(
model_name='assooption',
name='description',
field=models.TextField(blank=True, help_text="Description de l'asso", null=True),
),
migrations.AlterField(
model_name='assooption',
name='name',
field=models.CharField(default='Association réseau école machin', help_text="Nom complet de l'asso", max_length=256),
),
migrations.AlterField(
model_name='assooption',
name='payment',
field=models.CharField(choices=[('NONE', 'NONE'), ('COMNPAY', 'COMNPAY')], default='NONE', help_text='Mode de paiement en ligne', max_length=255),
),
migrations.AlterField(
model_name='assooption',
name='payment_id',
field=models.CharField(blank=True, default='', help_text='Id de paiement en ligne', max_length=255),
),
migrations.AlterField(
model_name='assooption',
name='payment_pass',
field=preferences.aes_field.AESEncryptedField(blank=True, help_text='Clef de paiement en ligne', max_length=255, null=True),
),
migrations.AlterField(
model_name='assooption',
name='pseudo',
field=models.CharField(default='Asso', help_text="Pseudo de l'asso", max_length=32),
),
migrations.AlterField(
model_name='assooption',
name='siret',
field=models.CharField(default='00000000000000', help_text='Numero SIRET', max_length=32),
),
migrations.AlterField(
model_name='assooption',
name='telephone',
field=models.CharField(default='0000000000', help_text='Téléphone de contact', max_length=15),
),
migrations.AlterField(
model_name='assooption',
name='utilisateur_asso',
field=models.OneToOneField(blank=True, help_text="Utilisateur dans la db correspondant à l'asso", null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='generaloption',
name='GTU',
field=models.FileField(blank=True, default='', help_text="CGU et documents réglementaires à l'inscription", null=True, upload_to=''),
),
migrations.AlterField(
model_name='generaloption',
name='GTU_sum_up',
field=models.TextField(blank=True, default='', help_text="Résumé des CGU à l'inscription"),
),
migrations.AlterField(
model_name='generaloption',
name='email_from',
field=models.EmailField(default='www-data@example.com', help_text='From des mails envoyés par re2o', max_length=254),
),
migrations.AlterField(
model_name='generaloption',
name='general_message',
field=models.TextField(blank=True, default='', help_text='Message général affiché sur le site (maintenance, etc)'),
),
migrations.AlterField(
model_name='generaloption',
name='pagination_large_number',
field=models.IntegerField(default=8, help_text="Nombre d'item par page paginée, items larges"),
),
migrations.AlterField(
model_name='generaloption',
name='pagination_number',
field=models.IntegerField(default=25, help_text="Nombre d'item par page paginée"),
),
migrations.AlterField(
model_name='generaloption',
name='req_expire_hrs',
field=models.IntegerField(default=48, help_text="Delais d'expiration des token changement de mdp, en heure"),
),
migrations.AlterField(
model_name='generaloption',
name='search_display_page',
field=models.IntegerField(default=15, help_text='Nombre de résultats affichés dans une recherche'),
),
migrations.AlterField(
model_name='generaloption',
name='site_name',
field=models.CharField(default='Re2o', help_text='Nom du site web, par defaut re2o', max_length=32),
),
migrations.AlterField(
model_name='optionalmachine',
name='ipv6_mode',
field=models.CharField(choices=[('SLAAC', 'Autoconfiguration par RA'), ('DHCPV6', 'Attribution des ip par dhcpv6'), ('DISABLED', 'Désactivé')], default='DISABLED', help_text='Mode ipv6', max_length=32),
),
migrations.AlterField(
model_name='optionalmachine',
name='max_lambdauser_aliases',
field=models.IntegerField(default=10, help_text='Maximum de cname pour un user sans droits'),
),
migrations.AlterField(
model_name='optionalmachine',
name='max_lambdauser_interfaces',
field=models.IntegerField(default=10, help_text="Maximum d'interface pour un user sans droits"),
),
migrations.AlterField(
model_name='optionalmachine',
name='password_machine',
field=models.BooleanField(default=False, help_text='Un mot de passe par machine activé'),
),
migrations.AlterField(
model_name='optionaltopologie',
name='radius_general_policy',
field=models.CharField(choices=[('MACHINE', 'Sur le vlan de la plage ip machine'), ('DEFINED', 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"')], default='DEFINED', help_text='Politique par defaut de placement de vlan avec radius', max_length=32),
),
migrations.AlterField(
model_name='optionaltopologie',
name='vlan_decision_nok',
field=models.OneToOneField(blank=True, help_text='Placement par defaut sur ce vlan en cas de rejet', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_nok', to='machines.Vlan'),
),
migrations.AlterField(
model_name='optionaltopologie',
name='vlan_decision_ok',
field=models.OneToOneField(blank=True, help_text="Placement sur ce vlan par default en cas d'accès OK", null=True, on_delete=django.db.models.deletion.PROTECT, related_name='decision_ok', to='machines.Vlan'),
),
migrations.AlterField(
model_name='optionaluser',
name='gpg_fingerprint',
field=models.BooleanField(default=True, help_text='Gpg fingerprint activée'),
),
migrations.AlterField(
model_name='optionaluser',
name='is_tel_mandatory',
field=models.BooleanField(default=True, help_text='Obligation de renseigner le téléphone'),
),
migrations.AlterField(
model_name='optionaluser',
name='max_solde',
field=models.DecimalField(decimal_places=2, default=50, help_text='Valeur maximum du solde', max_digits=5),
),
migrations.AlterField(
model_name='optionaluser',
name='min_online_payment',
field=models.DecimalField(decimal_places=2, default=10, help_text='Montant minimum pour le rechargement online', max_digits=5),
),
migrations.AlterField(
model_name='optionaluser',
name='shell_default',
field=models.OneToOneField(blank=True, help_text='Shell par default', null=True, on_delete=django.db.models.deletion.PROTECT, to='users.ListShell'),
),
migrations.AlterField(
model_name='optionaluser',
name='solde_negatif',
field=models.DecimalField(decimal_places=2, default=0, help_text='Maximum de négatif autorisé', max_digits=5),
),
migrations.AlterField(
model_name='optionaluser',
name='user_solde',
field=models.BooleanField(default=False, help_text='Solde pour les users'),
),
migrations.AlterField(
model_name='reminder',
name='message',
field=models.CharField(blank=True, default='', help_text='Message affiché spécifiquement pour ce rappel', max_length=255, null=True),
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-03 19:57
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0040_auto_20180703_0743'),
]
operations = [
migrations.AddField(
model_name='generaloption',
name='site_url',
field=models.CharField(default='re2o.org', help_text='url par défaut du site. par défaut: re2o.org', max_length=32),
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-03 20:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('preferences', '0041_generaloption_site_url'),
]
operations = [
migrations.AlterField(
model_name='generaloption',
name='site_url',
field=models.CharField(default='re2o.example.org', help_text='url par défaut du site. par défaut: re2o.example.org', max_length=32),
),
]

View file

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-09 17:47
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('machines', '0092_auto_20180708_2018'),
('preferences', '0042_auto_20180703_2222'),
]
operations = [
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_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'),
),
]

View file

@ -35,6 +35,7 @@ from django.core.cache import cache
from django.forms import ValidationError from django.forms import ValidationError
import cotisations.models import cotisations.models
import machines.models import machines.models
from re2o.mixins import AclMixin from re2o.mixins import AclMixin
@ -248,6 +249,26 @@ class OptionalTopologie(AclMixin, PreferencesModel):
null=True, null=True,
help_text="Placement par defaut sur ce vlan en cas de rejet" help_text="Placement par defaut sur ce vlan en cas de rejet"
) )
switchs_web_management = models.BooleanField(
default=False,
help_text="Web management, activé si provision automatique"
)
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"
)
@cached_property
def provisioned_switchs(self):
from topologie.models import Switch
return Switch.objects.filter(automatic_provision=True)
class Meta: class Meta:
permissions = ( permissions = (
@ -326,6 +347,11 @@ class GeneralOption(AclMixin, PreferencesModel):
default="Re2o", default="Re2o",
help_text="Nom du site web, par defaut re2o" help_text="Nom du site web, par defaut re2o"
) )
site_url = models.CharField(
max_length=32,
default="re2o.example.org",
help_text="url par défaut du site. par défaut: re2o.example.org"
)
email_from = models.EmailField( email_from = models.EmailField(
default="www-data@example.com", default="www-data@example.com",
help_text="From des mails envoyés par re2o" help_text="From des mails envoyés par re2o"

View file

@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>Nombre de jours avant le rappel</th> <th>Nombre de jours avant la fin d'adhésion</th>
<th>Message custom pour ce rappel</th> <th>Message custom pour ce rappel</th>
<th></th> <th></th>
<th></th> <th></th>

View file

@ -111,15 +111,41 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</a> </a>
<p> <p>
</p> </p>
<h5>Préférences authentification radius</h5>
<table class="table table-striped"> <table class="table table-striped">
{% for line in topologieoptions %}
<tr> <tr>
{% for text, field in line %} <th>Politique par defaut de placement de vlan avec radius</th>
<th>{{ field }}</th> <td>{{ topologieoptions.radius_general_policy }}</td>
<td>{{ text }}</td> <th>Placement sur ce vlan par default en cas d'accès OK</th>
{% endfor %} <td>{{ topologieoptions.vlan_decision_ok }}</td>
</tr>
<tr>
<th>Placement sur ce vlan par default en cas de rejet</th>
<td>{{ topologieoptions.vlan_decision_nok }}</td>
</tr>
</table>
<h5>Configuration des switches</h5>
<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>
<tr>
<th>Plage d'ip de management des switchs</th>
<td>{{ topologieoptions.switchs_ip_type }}</td>
</tr>
</table>
<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> </tr>
{% endfor %}
</table> </table>
<h4>Préférences generales</h4> <h4>Préférences generales</h4>

View file

@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<form class="form" method="post" enctype="multipart/form-data"> <form class="form" method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{% massive_bootstrap_form options 'utilisateur_asso' %} {% massive_bootstrap_form options 'utilisateur_asso' %}
{% massive_bootstrap_form options 'automatic_provision_switchs' %}
{% bootstrap_button "Modifier" button_type="submit" icon="star" %} {% bootstrap_button "Modifier" button_type="submit" icon="star" %}
</form> </form>
<br /> <br />

View file

@ -87,9 +87,9 @@ def display_options(request):
mailcontact_list = MailContact.objects.all() mailcontact_list = MailContact.objects.all()
reminder_list = Reminder.objects.all() reminder_list = Reminder.objects.all()
return form({ return form({
'useroptions': format_options(useroptions), 'useroptions': useroptions,
'machineoptions': format_options(machineoptions), 'machineoptions': format_options(machineoptions),
'topologieoptions': format_options(topologieoptions), 'topologieoptions': topologieoptions,
'generaloptions': format_options(generaloptions), 'generaloptions': format_options(generaloptions),
'assooptions': format_options(assooptions), 'assooptions': format_options(assooptions),
'homeoptions': format_options(homeoptions), 'homeoptions': format_options(homeoptions),

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-09 17:47
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('topologie', '0068_modelswitch_firmware'),
]
operations = [
migrations.AddField(
model_name='switch',
name='automatic_provision',
field=models.BooleanField(default=False, help_text='Provision automatique de ce switch'),
),
]

View file

@ -49,6 +49,7 @@ from django.db import transaction
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from reversion import revisions as reversion from reversion import revisions as reversion
from preferences.models import OptionalTopologie
from machines.models import Machine, regen from machines.models import Machine, regen
from re2o.mixins import AclMixin, RevMixin from re2o.mixins import AclMixin, RevMixin
@ -216,6 +217,10 @@ class Switch(AclMixin, Machine):
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
help_text="Baie de brassage du switch" help_text="Baie de brassage du switch"
) )
automatic_provision = models.BooleanField(
default=False,
help_text='Provision automatique de ce switch',
)
class Meta: class Meta:
unique_together = ('stack', 'stack_member_id') unique_together = ('stack', 'stack_member_id')
@ -271,6 +276,14 @@ class Switch(AclMixin, Machine):
""" Returns the 'main' interface of the switch """ """ Returns the 'main' interface of the switch """
return self.interface_set.first() return self.interface_set.first()
@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):
return OptionalTopologie.get_cached_value('switchs_web_management') or self.automatic_provision
@cached_property @cached_property
def ipv4(self): def ipv4(self):
return str(self.main_interface().ipv4) return str(self.main_interface().ipv4)