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:
parent
e7f301c392
commit
d1131d732f
12 changed files with 377 additions and 10 deletions
|
@ -40,6 +40,7 @@ from .models import (
|
|||
MailContact,
|
||||
Reminder
|
||||
)
|
||||
from topologie.models import Switch
|
||||
|
||||
class EditOptionalUserForm(ModelForm):
|
||||
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
|
||||
|
@ -77,7 +78,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__'
|
||||
|
@ -94,6 +102,14 @@ class EditOptionalTopologieForm(ModelForm):
|
|||
self.fields['vlan_decision_nok'].label = "Vlan où placer les\
|
||||
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):
|
||||
"""Options générales (affichages de résultats de recherche, etc)"""
|
||||
|
|
193
preferences/migrations/0040_auto_20180703_0743.py
Normal file
193
preferences/migrations/0040_auto_20180703_0743.py
Normal 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),
|
||||
),
|
||||
]
|
20
preferences/migrations/0041_generaloption_site_url.py
Normal file
20
preferences/migrations/0041_generaloption_site_url.py
Normal 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),
|
||||
),
|
||||
]
|
20
preferences/migrations/0042_auto_20180703_2222.py
Normal file
20
preferences/migrations/0042_auto_20180703_2222.py
Normal 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),
|
||||
),
|
||||
]
|
32
preferences/migrations/0043_auto_20180709_1947.py
Normal file
32
preferences/migrations/0043_auto_20180709_1947.py
Normal 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'),
|
||||
),
|
||||
]
|
|
@ -35,6 +35,7 @@ from django.core.cache import cache
|
|||
from django.forms import ValidationError
|
||||
import cotisations.models
|
||||
import machines.models
|
||||
|
||||
from re2o.mixins import AclMixin
|
||||
|
||||
|
||||
|
@ -248,6 +249,26 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
null=True,
|
||||
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:
|
||||
permissions = (
|
||||
|
@ -326,6 +347,11 @@ class GeneralOption(AclMixin, PreferencesModel):
|
|||
default="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(
|
||||
default="www-data@example.com",
|
||||
help_text="From des mails envoyés par re2o"
|
||||
|
|
|
@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<table class="table table-striped">
|
||||
<thead>
|
||||
<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></th>
|
||||
<th></th>
|
||||
|
|
|
@ -111,15 +111,41 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
</a>
|
||||
<p>
|
||||
</p>
|
||||
<h5>Préférences authentification radius</h5>
|
||||
<table class="table table-striped">
|
||||
{% for line in topologieoptions %}
|
||||
<tr>
|
||||
{% for text, field in line %}
|
||||
<th>{{ field }}</th>
|
||||
<td>{{ text }}</td>
|
||||
{% endfor %}
|
||||
<th>Politique par defaut de placement de vlan avec radius</th>
|
||||
<td>{{ topologieoptions.radius_general_policy }}</td>
|
||||
<th>Placement sur ce vlan par default en cas d'accès OK</th>
|
||||
<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>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<h4>Préférences generales</h4>
|
||||
|
|
|
@ -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">
|
||||
{% csrf_token %}
|
||||
{% massive_bootstrap_form options 'utilisateur_asso' %}
|
||||
{% massive_bootstrap_form options 'automatic_provision_switchs' %}
|
||||
{% bootstrap_button "Modifier" button_type="submit" icon="star" %}
|
||||
</form>
|
||||
<br />
|
||||
|
|
|
@ -87,9 +87,9 @@ def display_options(request):
|
|||
mailcontact_list = MailContact.objects.all()
|
||||
reminder_list = Reminder.objects.all()
|
||||
return form({
|
||||
'useroptions': format_options(useroptions),
|
||||
'useroptions': useroptions,
|
||||
'machineoptions': format_options(machineoptions),
|
||||
'topologieoptions': format_options(topologieoptions),
|
||||
'topologieoptions': topologieoptions,
|
||||
'generaloptions': format_options(generaloptions),
|
||||
'assooptions': format_options(assooptions),
|
||||
'homeoptions': format_options(homeoptions),
|
||||
|
|
20
topologie/migrations/0069_switch_automatic_provision.py
Normal file
20
topologie/migrations/0069_switch_automatic_provision.py
Normal 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'),
|
||||
),
|
||||
]
|
|
@ -49,6 +49,7 @@ from django.db import transaction
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from reversion import revisions as reversion
|
||||
|
||||
from preferences.models import OptionalTopologie
|
||||
from machines.models import Machine, regen
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
|
||||
|
@ -216,6 +217,10 @@ class Switch(AclMixin, Machine):
|
|||
on_delete=models.SET_NULL,
|
||||
help_text="Baie de brassage du switch"
|
||||
)
|
||||
automatic_provision = models.BooleanField(
|
||||
default=False,
|
||||
help_text='Provision automatique de ce switch',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('stack', 'stack_member_id')
|
||||
|
@ -271,6 +276,14 @@ class Switch(AclMixin, Machine):
|
|||
""" Returns the 'main' interface of the switch """
|
||||
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
|
||||
def ipv4(self):
|
||||
return str(self.main_interface().ipv4)
|
||||
|
|
Loading…
Reference in a new issue