From 02229983a024fdce8020ffd60649a1f303841031 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 30 Dec 2018 11:27:54 +0100 Subject: [PATCH 01/10] =?UTF-8?q?Exporte=20la=20liste=20des=20r=C3=A9cursi?= =?UTF-8?q?fs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- preferences/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/preferences/models.py b/preferences/models.py index 4644aa1c..e8476354 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -278,12 +278,13 @@ class OptionalTopologie(AclMixin, PreferencesModel): 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") + dns_recursive_servers = Role.all_interfaces_for_roletype("dns-recursif-server").filter(type__ip_type=self.switchs_ip_type) 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} + 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), 'dns_recursive_servers': return_ips_dict(dns_recursive_servers), 'subnet': subnet, 'subnet6': subnet6} @cached_property def provision_switchs_enabled(self): From 2c9ff4ea8e7c78e226cead8b2fb179d0b5a91ece Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 30 Dec 2018 17:04:21 +0100 Subject: [PATCH 02/10] Module switch, model et fonctions basiques de modification --- topologie/forms.py | 21 ++++++ .../migrations/0067_auto_20181230_1556.py | 63 +++++++++++++++++ topologie/models.py | 64 +++++++++++++++++ .../templates/topologie/aff_modules.html | 67 ++++++++++++++++++ .../templates/topologie/index_module.html | 43 ++++++++++++ topologie/templates/topologie/sidebar.html | 4 ++ topologie/templates/topologie/topo.html | 2 +- topologie/urls.py | 8 ++- topologie/views.py | 70 +++++++++++++++++++ 9 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 topologie/migrations/0067_auto_20181230_1556.py create mode 100644 topologie/templates/topologie/aff_modules.html create mode 100644 topologie/templates/topologie/index_module.html diff --git a/topologie/forms.py b/topologie/forms.py index fa089507..dc4a5e9b 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -55,6 +55,7 @@ from .models import ( SwitchBay, Building, PortProfile, + ModuleSwitch ) @@ -269,3 +270,23 @@ class EditPortProfileForm(FormRevMixin, ModelForm): prefix=prefix, **kwargs) +class EditModuleForm(FormRevMixin, ModelForm): + """Add and edit module instance""" + class Meta: + model = ModuleSwitch + fields = '__all__' + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(EditModuleForm, self).__init__(*args, prefix=prefix, **kwargs) + self.fields['switchs'].queryset = (Switch.objects.filter(model__is_modular=True)) + + def save(self, commit=True): + # TODO : None of the parents of ServiceForm use the commit + # parameter in .save() + instance = super(EditModuleForm, self).save(commit=False) + if commit: + instance.save() + instance.process_link(self.cleaned_data.get('switchs')) + return instance + diff --git a/topologie/migrations/0067_auto_20181230_1556.py b/topologie/migrations/0067_auto_20181230_1556.py new file mode 100644 index 00000000..cd0d368c --- /dev/null +++ b/topologie/migrations/0067_auto_20181230_1556.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-12-30 14:56 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import re2o.mixins + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0066_modelswitch_commercial_name'), + ] + + operations = [ + migrations.CreateModel( + name='ModuleOnSwitch', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('slot', models.CharField(help_text='Slot on switch', max_length=15, verbose_name='Slot')), + ], + options={ + 'verbose_name': 'link between switchs and modules', + 'permissions': (('view_moduleonswitch', 'Can view a moduleonswitch object'),), + }, + bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), + ), + migrations.CreateModel( + name='ModuleSwitch', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('reference', models.CharField(help_text='Reference of a module', max_length=255, verbose_name='Module reference')), + ('comment', models.CharField(blank=True, help_text='Comment', max_length=255, null=True, verbose_name='Comment')), + ('switchs', models.ManyToManyField(through='topologie.ModuleOnSwitch', to='topologie.Switch')), + ], + options={ + 'verbose_name': 'Module of a switch', + 'permissions': (('view_moduleswitch', 'Can view a module object'),), + }, + bases=(re2o.mixins.AclMixin, re2o.mixins.RevMixin, models.Model), + ), + migrations.AddField( + model_name='modelswitch', + name='is_itself_module', + field=models.BooleanField(default=False, help_text='Does the switch, itself, considered as a module'), + ), + migrations.AddField( + model_name='modelswitch', + name='is_modular', + field=models.BooleanField(default=False, help_text='Is this switch model modular'), + ), + migrations.AddField( + model_name='moduleonswitch', + name='module', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='topologie.ModuleSwitch'), + ), + migrations.AddField( + model_name='moduleonswitch', + name='switch', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='topologie.Switch'), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index e08a1b21..a4f5f3bc 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -251,6 +251,7 @@ class Switch(AclMixin, Machine): default=False, help_text='Provision automatique de ce switch', ) + class Meta: unique_together = ('stack', 'stack_member_id') @@ -389,6 +390,14 @@ class ModelSwitch(AclMixin, RevMixin, models.Model): null=True, blank=True ) + is_modular = models.BooleanField( + default=False, + help_text=_("Is this switch model modular"), + ) + is_itself_module = models.BooleanField( + default=False, + help_text=_("Does the switch, itself, considered as a module"), + ) class Meta: permissions = ( @@ -404,6 +413,61 @@ class ModelSwitch(AclMixin, RevMixin, models.Model): return str(self.constructor) + ' ' + self.reference +class ModuleSwitch(AclMixin, RevMixin, models.Model): + """A module of a switch""" + reference = models.CharField( + max_length=255, + help_text=_("Reference of a module"), + verbose_name=_("Module reference") + ) + comment = models.CharField( + max_length=255, + null=True, + blank=True, + help_text=_("Comment"), + verbose_name=_("Comment") + ) + switchs = models.ManyToManyField('Switch', through='ModuleOnSwitch') + + class Meta: + permissions = ( + ("view_moduleswitch", _("Can view a module object")), + ) + verbose_name = _("Module of a switch") + + def process_link(self, switchs): + """Django can't create itself foreignkey with explicit through""" + ModuleOnSwitch.objects.bulk_create( + [ModuleOnSwitch( + module=self, switch=sw + ) for sw in switchs.exclude( + pk__in=Switch.objects.filter(moduleswitch=self) + )] + ) + ModuleOnSwitch.objects.filter(module=self).exclude(switch__in=switchs).delete() + return + + def __str__(self): + return str(self.reference) + + +class ModuleOnSwitch(AclMixin, RevMixin, models.Model): + """Link beetween module and switch""" + module = models.ForeignKey('ModuleSwitch', on_delete=models.CASCADE) + switch = models.ForeignKey('Switch', on_delete=models.CASCADE) + slot = models.CharField( + max_length=15, + help_text=_("Slot on switch"), + verbose_name=_("Slot") + ) + + class Meta: + permissions = ( + ("view_moduleonswitch", _("Can view a moduleonswitch object")), + ) + verbose_name = _("link between switchs and modules") + + class ConstructorSwitch(AclMixin, RevMixin, models.Model): """Un constructeur de switch""" diff --git a/topologie/templates/topologie/aff_modules.html b/topologie/templates/topologie/aff_modules.html new file mode 100644 index 00000000..8233260c --- /dev/null +++ b/topologie/templates/topologie/aff_modules.html @@ -0,0 +1,67 @@ +{% 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 %} +{% load i18n %} + +{% if module_list.paginator %} +{% include "pagination.html" with list=module_list %} +{% endif %} + + + + + + + + + + + {% for module in module_list %} + + + + + + + {% endfor %} +
{% trans "Reference" %}{% trans "Comment" %}{% trans "Switchs" %}
{{ module.reference }}{{ module.comment }}{{ module.switchs.all }} + {% can_edit module %} + + + + {% acl_end %} + {% history_button module %} + {% can_delete module %} + + + + {% acl_end %} +
+ +{% if module_list.paginator %} +{% include "pagination.html" with list=module_list %} +{% endif %} + diff --git a/topologie/templates/topologie/index_module.html b/topologie/templates/topologie/index_module.html new file mode 100644 index 00000000..5c4c5c7c --- /dev/null +++ b/topologie/templates/topologie/index_module.html @@ -0,0 +1,43 @@ +{% 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 %} +{% load acl %} +{% load i18n %} + +{% block title %}{% trans "Topology" %}{% endblock %} + +{% block content %} +

{% trans "Modules of switchs" %}

+{% can_create ModuleSwitch %} +{% trans " Add a module" %} +
+{% acl_end %} + {% include "topologie/aff_modules.html" with module_list=module_list %} +
+
+
+{% endblock %} + diff --git a/topologie/templates/topologie/sidebar.html b/topologie/templates/topologie/sidebar.html index a35721f9..80317a16 100644 --- a/topologie/templates/topologie/sidebar.html +++ b/topologie/templates/topologie/sidebar.html @@ -33,6 +33,10 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Switches" %} + + + + {% trans "Switches modules" %} diff --git a/topologie/templates/topologie/topo.html b/topologie/templates/topologie/topo.html index bf9f760b..d1ec9bb3 100644 --- a/topologie/templates/topologie/topo.html +++ b/topologie/templates/topologie/topo.html @@ -37,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endif %}
{% csrf_token %} - {% massive_bootstrap_form topoform 'room,related,machine_interface,members,vlan_tagged' %} + {% massive_bootstrap_form topoform 'room,related,machine_interface,members,vlan_tagged,switchs' %} {% bootstrap_button action_name icon='ok' button_class='btn-success' %}

diff --git a/topologie/urls.py b/topologie/urls.py index 77d68d50..7af7df9a 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -123,4 +123,10 @@ urlpatterns = [ url(r'^edit_vlanoptions/(?P[0-9]+)$', views.edit_vlanoptions, name='edit-vlanoptions'), - ] + url(r'^add_module/$', views.add_module, name='add-module'), + url(r'^edit_module/(?P[0-9]+)$', + views.edit_module, + name='edit-module'), + url(r'^del_module/(?P[0-9]+)$', views.del_module, name='del-module'), + url(r'^index_module/$', views.index_module, name='index-module'), +] diff --git a/topologie/views.py b/topologie/views.py index 89d48b0b..f5c72627 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -86,6 +86,7 @@ from .models import ( Building, Server, PortProfile, + ModuleSwitch, ) from .forms import ( EditPortForm, @@ -102,6 +103,7 @@ from .forms import ( EditSwitchBayForm, EditBuildingForm, EditPortProfileForm, + EditModuleForm ) from subprocess import ( @@ -316,6 +318,20 @@ def index_model_switch(request): ) +@login_required +@can_view_all(ModuleSwitch) +def index_module(request): + """Display all modules of switchs""" + module_list = ModuleSwitch.objects.all() + pagination_number = GeneralOption.get_cached_value('pagination_number') + module_list = re2o_paginator(request, module_list, pagination_number) + return render( + request, + 'topologie/index_module.html', + {'module_list': module_list} + ) + + @login_required @can_edit(Vlan) def edit_vlanoptions(request, vlan_instance, **_kwargs): @@ -1048,6 +1064,60 @@ def del_port_profile(request, port_profile, **_kwargs): ) +@can_create(ModuleSwitch) +def add_module(request): + """ View used to add a Module object """ + module = EditModuleForm(request.POST or None) + if module.is_valid(): + module.save() + messages.success(request, _("The module was created.")) + return redirect(reverse('topologie:index-module')) + return form( + {'topoform': module, 'action_name': _("Create a module")}, + 'topologie/topo.html', + request + ) + + +@login_required +@can_edit(ModuleSwitch) +def edit_module(request, module_instance, **_kwargs): + """ View used to edit a Module object """ + module = EditModuleForm(request.POST or None, instance=module_instance) + if module.is_valid(): + if module.changed_data: + module.save() + messages.success(request, _("The module was edited.")) + return redirect(reverse('topologie:index-module')) + return form( + {'topoform': module, 'action_name': _("Edit")}, + 'topologie/topo.html', + request + ) + + +@login_required +@can_delete(ModuleSwitch) +def del_module(request, module, **_kwargs): + """Compleete delete a module""" + if request.method == "POST": + try: + module.delete() + messages.success(request, _("The module was deleted.")) + except ProtectedError: + messages.error( + request, + (_("The module %s is used by another object, impossible to" + " deleted it.") % module) + ) + return redirect(reverse('topologie:index-module')) + return form( + {'objet': module, 'objet_name': _("Module")}, + 'topologie/delete.html', + request + ) + + def make_machine_graph(): """ Create the graph of switchs, machines and access points. From 4dbbb00cf7fc4867ce1ef0c2258600d54b150cf0 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 30 Dec 2018 17:16:30 +0100 Subject: [PATCH 03/10] Export of modules of a switch --- topologie/models.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/topologie/models.py b/topologie/models.py index a4f5f3bc..53e9ffe6 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -368,6 +368,17 @@ class Switch(AclMixin, Machine): """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()) + @cached_property + def list_modules(self): + """Return modules of that switch, list of dict (rank, reference)""" + modules = [] + if self.model.is_modular: + if self.model.is_itself_module: + modules.append((1, self.model.reference)) + for module_of_self in self.moduleonswitch_set.all(): + modules.append((module_of_self.slot, module_of_self.module.reference)) + return modules + def __str__(self): return str(self.get_name) From 683cf229e96fe4c9539a201790a32d8b126072cc Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 30 Dec 2018 18:20:06 +0100 Subject: [PATCH 04/10] Edition fine des modules pour chaque switchs avec le slot --- topologie/forms.py | 21 +++---- ...230_1556.py => 0067_auto_20181230_1819.py} | 7 ++- topologie/models.py | 16 ++--- .../templates/topologie/aff_modules.html | 20 ++++++- topologie/templates/topologie/topo.html | 2 +- topologie/urls.py | 9 ++- topologie/views.py | 59 ++++++++++++++++++- 7 files changed, 105 insertions(+), 29 deletions(-) rename topologie/migrations/{0067_auto_20181230_1556.py => 0067_auto_20181230_1819.py} (93%) diff --git a/topologie/forms.py b/topologie/forms.py index dc4a5e9b..ed6fa5b9 100644 --- a/topologie/forms.py +++ b/topologie/forms.py @@ -55,7 +55,8 @@ from .models import ( SwitchBay, Building, PortProfile, - ModuleSwitch + ModuleSwitch, + ModuleOnSwitch, ) @@ -279,14 +280,14 @@ class EditModuleForm(FormRevMixin, ModelForm): def __init__(self, *args, **kwargs): prefix = kwargs.pop('prefix', self.Meta.model.__name__) super(EditModuleForm, self).__init__(*args, prefix=prefix, **kwargs) - self.fields['switchs'].queryset = (Switch.objects.filter(model__is_modular=True)) - def save(self, commit=True): - # TODO : None of the parents of ServiceForm use the commit - # parameter in .save() - instance = super(EditModuleForm, self).save(commit=False) - if commit: - instance.save() - instance.process_link(self.cleaned_data.get('switchs')) - return instance +class EditSwitchModuleForm(FormRevMixin, ModelForm): + """Add/edit a switch to a module""" + class Meta: + model = ModuleOnSwitch + fields = '__all__' + + def __init__(self, *args, **kwargs): + prefix = kwargs.pop('prefix', self.Meta.model.__name__) + super(EditSwitchModuleForm, self).__init__(*args, prefix=prefix, **kwargs) diff --git a/topologie/migrations/0067_auto_20181230_1556.py b/topologie/migrations/0067_auto_20181230_1819.py similarity index 93% rename from topologie/migrations/0067_auto_20181230_1556.py rename to topologie/migrations/0067_auto_20181230_1819.py index cd0d368c..57f268ea 100644 --- a/topologie/migrations/0067_auto_20181230_1556.py +++ b/topologie/migrations/0067_auto_20181230_1819.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.7 on 2018-12-30 14:56 +# Generated by Django 1.10.7 on 2018-12-30 17:19 from __future__ import unicode_literals from django.db import migrations, models @@ -32,7 +32,6 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('reference', models.CharField(help_text='Reference of a module', max_length=255, verbose_name='Module reference')), ('comment', models.CharField(blank=True, help_text='Comment', max_length=255, null=True, verbose_name='Comment')), - ('switchs', models.ManyToManyField(through='topologie.ModuleOnSwitch', to='topologie.Switch')), ], options={ 'verbose_name': 'Module of a switch', @@ -60,4 +59,8 @@ class Migration(migrations.Migration): name='switch', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='topologie.Switch'), ), + migrations.AlterUniqueTogether( + name='moduleonswitch', + unique_together=set([('slot', 'switch')]), + ), ] diff --git a/topologie/models.py b/topologie/models.py index 53e9ffe6..b2c75f24 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -438,7 +438,6 @@ class ModuleSwitch(AclMixin, RevMixin, models.Model): help_text=_("Comment"), verbose_name=_("Comment") ) - switchs = models.ManyToManyField('Switch', through='ModuleOnSwitch') class Meta: permissions = ( @@ -446,17 +445,6 @@ class ModuleSwitch(AclMixin, RevMixin, models.Model): ) verbose_name = _("Module of a switch") - def process_link(self, switchs): - """Django can't create itself foreignkey with explicit through""" - ModuleOnSwitch.objects.bulk_create( - [ModuleOnSwitch( - module=self, switch=sw - ) for sw in switchs.exclude( - pk__in=Switch.objects.filter(moduleswitch=self) - )] - ) - ModuleOnSwitch.objects.filter(module=self).exclude(switch__in=switchs).delete() - return def __str__(self): return str(self.reference) @@ -477,6 +465,10 @@ class ModuleOnSwitch(AclMixin, RevMixin, models.Model): ("view_moduleonswitch", _("Can view a moduleonswitch object")), ) verbose_name = _("link between switchs and modules") + unique_together = ['slot', 'switch'] + + def __str__(self): + return 'On slot ' + str(self.slot) + ' of ' + str(self.switch) class ConstructorSwitch(AclMixin, RevMixin, models.Model): diff --git a/topologie/templates/topologie/aff_modules.html b/topologie/templates/topologie/aff_modules.html index 8233260c..d73fffeb 100644 --- a/topologie/templates/topologie/aff_modules.html +++ b/topologie/templates/topologie/aff_modules.html @@ -43,9 +43,27 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ module.reference }} {{ module.comment }} - {{ module.switchs.all }} + + {% for module_switch in module.moduleonswitch_set.all %} + Slot {{ module_switch.slot }} of {{ module_switch.switch }} + {% can_edit module_switch %} +
+ + + {% acl_end %} + {% can_delete module_switch %} + + + + {% acl_end %} +
+ {% endfor %} + {% can_edit module %} + + + diff --git a/topologie/templates/topologie/topo.html b/topologie/templates/topologie/topo.html index d1ec9bb3..a7824020 100644 --- a/topologie/templates/topologie/topo.html +++ b/topologie/templates/topologie/topo.html @@ -37,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% endif %}
{% csrf_token %} - {% massive_bootstrap_form topoform 'room,related,machine_interface,members,vlan_tagged,switchs' %} + {% massive_bootstrap_form topoform 'room,related,machine_interface,members,vlan_tagged,switch' %} {% bootstrap_button action_name icon='ok' button_class='btn-success' %}

diff --git a/topologie/urls.py b/topologie/urls.py index 7af7df9a..70eae8e4 100644 --- a/topologie/urls.py +++ b/topologie/urls.py @@ -124,9 +124,14 @@ urlpatterns = [ views.edit_vlanoptions, name='edit-vlanoptions'), url(r'^add_module/$', views.add_module, name='add-module'), - url(r'^edit_module/(?P[0-9]+)$', + url(r'^edit_module/(?P[0-9]+)$', views.edit_module, name='edit-module'), - url(r'^del_module/(?P[0-9]+)$', views.del_module, name='del-module'), + url(r'^del_module/(?P[0-9]+)$', views.del_module, name='del-module'), url(r'^index_module/$', views.index_module, name='index-module'), + url(r'^add_module_on/$', views.add_module_on, name='add-module-on'), + url(r'^edit_module_on/(?P[0-9]+)$', + views.edit_module_on, + name='edit-module-on'), + url(r'^del_module_on/(?P[0-9]+)$', views.del_module_on, name='del-module-on'), ] diff --git a/topologie/views.py b/topologie/views.py index f5c72627..5174f05d 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -87,6 +87,7 @@ from .models import ( Server, PortProfile, ModuleSwitch, + ModuleOnSwitch, ) from .forms import ( EditPortForm, @@ -103,7 +104,8 @@ from .forms import ( EditSwitchBayForm, EditBuildingForm, EditPortProfileForm, - EditModuleForm + EditModuleForm, + EditSwitchModuleForm, ) from subprocess import ( @@ -1064,6 +1066,7 @@ def del_port_profile(request, port_profile, **_kwargs): ) +@login_required @can_create(ModuleSwitch) def add_module(request): """ View used to add a Module object """ @@ -1117,6 +1120,60 @@ def del_module(request, module, **_kwargs): request ) +@login_required +@can_create(ModuleOnSwitch) +def add_module_on(request): + """Add a module to a switch""" + module_switch = EditSwitchModuleForm(request.POST or None) + if module_switch.is_valid(): + module_switch.save() + messages.success(request, _("The module added to that switch")) + return redirect(reverse('topologie:index-module')) + return form( + {'topoform': module_switch, 'action_name': _("Create")}, + 'topologie/topo.html', + request + ) + + +@login_required +@can_edit(ModuleOnSwitch) +def edit_module_on(request, module_instance, **_kwargs): + """ View used to edit a Module object """ + module = EditSwitchModuleForm(request.POST or None, instance=module_instance) + if module.is_valid(): + if module.changed_data: + module.save() + messages.success(request, _("The module was edited.")) + return redirect(reverse('topologie:index-module')) + return form( + {'topoform': module, 'action_name': _("Edit")}, + 'topologie/topo.html', + request + ) + + +@login_required +@can_delete(ModuleOnSwitch) +def del_module_on(request, module, **_kwargs): + """Compleete delete a module""" + if request.method == "POST": + try: + module.delete() + messages.success(request, _("The module was deleted.")) + except ProtectedError: + messages.error( + request, + (_("The module %s is used by another object, impossible to" + " deleted it.") % module) + ) + return redirect(reverse('topologie:index-module')) + return form( + {'objet': module, 'objet_name': _("Module")}, + 'topologie/delete.html', + request + ) + def make_machine_graph(): """ From 82802de47706ed66299168d4e42d77f8bae02456 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 30 Dec 2018 18:45:18 +0100 Subject: [PATCH 05/10] More clear front of all switchs modular --- .../templates/topologie/aff_modules.html | 25 +++++++++++++++++++ .../templates/topologie/index_module.html | 2 +- topologie/views.py | 4 ++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/topologie/templates/topologie/aff_modules.html b/topologie/templates/topologie/aff_modules.html index d73fffeb..0c7a3207 100644 --- a/topologie/templates/topologie/aff_modules.html +++ b/topologie/templates/topologie/aff_modules.html @@ -83,3 +83,28 @@ with this program; if not, write to the Free Software Foundation, Inc., {% include "pagination.html" with list=module_list %} {% endif %} +

{% trans "All modular switchs" %}

+ + + + + + + + {% for switch in modular_switchs %} + {% if switch.list_modules %} + + + + {% for module in switch.list_modules %} + + + + + + {% endfor %} +{% endif %} +{% endfor %} +
{% trans "Switch" %}{% trans "Reference" %}{% trans "Slot" %}
+ {{ switch }} +
{{ module.1 }}{{ module.0 }}
diff --git a/topologie/templates/topologie/index_module.html b/topologie/templates/topologie/index_module.html index 5c4c5c7c..d9cc2925 100644 --- a/topologie/templates/topologie/index_module.html +++ b/topologie/templates/topologie/index_module.html @@ -35,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans " Add a module" %}
{% acl_end %} - {% include "topologie/aff_modules.html" with module_list=module_list %} + {% include "topologie/aff_modules.html" with module_list=module_list modular_switchs=modular_switchs %}


diff --git a/topologie/views.py b/topologie/views.py index 5174f05d..55f0a060 100644 --- a/topologie/views.py +++ b/topologie/views.py @@ -325,12 +325,14 @@ def index_model_switch(request): def index_module(request): """Display all modules of switchs""" module_list = ModuleSwitch.objects.all() + modular_switchs = Switch.objects.filter(model__is_modular=True) pagination_number = GeneralOption.get_cached_value('pagination_number') module_list = re2o_paginator(request, module_list, pagination_number) return render( request, 'topologie/index_module.html', - {'module_list': module_list} + {'module_list': module_list, + 'modular_switchs': modular_switchs} ) From 64301bda9f5e369e3f38a6e74b662f3e6f2e7478 Mon Sep 17 00:00:00 2001 From: Gabriel Detraz Date: Sun, 30 Dec 2018 19:22:43 +0100 Subject: [PATCH 06/10] Export list_modules + return [] if no models for modules --- api/serializers.py | 3 ++- topologie/models.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/serializers.py b/api/serializers.py index e7b23f32..af92e0d0 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -811,7 +811,8 @@ class SwitchPortSerializer(serializers.ModelSerializer): 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') + 'web_management_enabled', 'get_radius_key_value', 'get_management_cred_value', + 'list_modules') # LOCAL EMAILS diff --git a/topologie/models.py b/topologie/models.py index b2c75f24..fd054c43 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -372,7 +372,7 @@ class Switch(AclMixin, Machine): def list_modules(self): """Return modules of that switch, list of dict (rank, reference)""" modules = [] - if self.model.is_modular: + if getattr(self.model, 'is_modular', None): if self.model.is_itself_module: modules.append((1, self.model.reference)) for module_of_self in self.moduleonswitch_set.all(): From 80e20d0f91324c0c0f21fb23a83994b12c73c0b5 Mon Sep 17 00:00:00 2001 From: klafyvel Date: Tue, 1 Jan 2019 20:31:36 +0100 Subject: [PATCH 07/10] English is a beautiful language --- preferences/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preferences/models.py b/preferences/models.py index e8476354..104c261d 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -278,7 +278,7 @@ class OptionalTopologie(AclMixin, PreferencesModel): 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") - dns_recursive_servers = Role.all_interfaces_for_roletype("dns-recursif-server").filter(type__ip_type=self.switchs_ip_type) + dns_recursive_servers = Role.all_interfaces_for_roletype("dns-recursive-server").filter(type__ip_type=self.switchs_ip_type) subnet = None subnet6 = None if self.switchs_ip_type: From 80b8779c5579273ecc3b576fff18b821c19b8d26 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 3 Jan 2019 00:54:13 +0100 Subject: [PATCH 08/10] dns-recursif-server -> dns-recursive-server --- machines/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machines/models.py b/machines/models.py index 1cf840d7..a4685676 100644 --- a/machines/models.py +++ b/machines/models.py @@ -1612,7 +1612,7 @@ class Role(RevMixin, AclMixin, models.Model): ROLE = ( ('dhcp-server', _("DHCP server")), ('switch-conf-server', _("Switches configuration server")), - ('dns-recursif-server', _("Recursive DNS server")), + ('dns-recursive-server', _("Recursive DNS server")), ('ntp-server', _("NTP server")), ('radius-server', _("RADIUS server")), ('log-server', _("Log server")), From 2e3be7ad56f7c430e5a8ee98d1e0b4beb8466445 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 3 Jan 2019 00:54:54 +0100 Subject: [PATCH 09/10] migrations for recursive dns --- .../migrations/0098_auto_20190102_1745.py | 20 ++++++++++++++ .../migrations/0099_role_recursive_dns.py | 26 +++++++++++++++++++ .../migrations/0100_auto_20190102_1753.py | 20 ++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 machines/migrations/0098_auto_20190102_1745.py create mode 100644 machines/migrations/0099_role_recursive_dns.py create mode 100644 machines/migrations/0100_auto_20190102_1753.py diff --git a/machines/migrations/0098_auto_20190102_1745.py b/machines/migrations/0098_auto_20190102_1745.py new file mode 100644 index 00000000..e886e8a1 --- /dev/null +++ b/machines/migrations/0098_auto_20190102_1745.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-01-02 23:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0097_extension_dnssec'), + ] + + operations = [ + migrations.AlterField( + model_name='role', + name='specific_role', + field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursif-server', 'Recursive DNS server'), ('dns-recursive-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True), + ), + ] diff --git a/machines/migrations/0099_role_recursive_dns.py b/machines/migrations/0099_role_recursive_dns.py new file mode 100644 index 00000000..c1ce3965 --- /dev/null +++ b/machines/migrations/0099_role_recursive_dns.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-01-02 23:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def migrate(apps, schema_editor): + Role = apps.get_model('machines', 'Role') + + for role in Role.objects.filter(specific_role='dns-recursif-server'): + role.specific_role = 'dns-recursive-server' + role.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0098_auto_20190102_1745'), + ] + + operations = [ + migrations.RunPython(migrate), + ] + + diff --git a/machines/migrations/0100_auto_20190102_1753.py b/machines/migrations/0100_auto_20190102_1753.py new file mode 100644 index 00000000..35f7b78d --- /dev/null +++ b/machines/migrations/0100_auto_20190102_1753.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-01-02 23:53 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0099_role_recursive_dns'), + ] + + operations = [ + migrations.AlterField( + model_name='role', + name='specific_role', + field=models.CharField(blank=True, choices=[('dhcp-server', 'DHCP server'), ('switch-conf-server', 'Switches configuration server'), ('dns-recursive-server', 'Recursive DNS server'), ('ntp-server', 'NTP server'), ('radius-server', 'RADIUS server'), ('log-server', 'Log server'), ('ldap-master-server', 'LDAP master server'), ('ldap-backup-server', 'LDAP backup server'), ('smtp-server', 'SMTP server'), ('postgresql-server', 'postgreSQL server'), ('mysql-server', 'mySQL server'), ('sql-client', 'SQL client'), ('gateway', 'Gateway')], max_length=32, null=True), + ), + ] From af714a7f331982a311a3aca76926c1a928e3edcb Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 3 Jan 2019 01:02:02 +0100 Subject: [PATCH 10/10] typo --- .../migrations/0068_auto_20190102_1758.py | 20 +++++++++++++++++++ topologie/models.py | 14 ++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 topologie/migrations/0068_auto_20190102_1758.py diff --git a/topologie/migrations/0068_auto_20190102_1758.py b/topologie/migrations/0068_auto_20190102_1758.py new file mode 100644 index 00000000..b03e7ae5 --- /dev/null +++ b/topologie/migrations/0068_auto_20190102_1758.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-01-02 23:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('topologie', '0067_auto_20181230_1819'), + ] + + operations = [ + migrations.AlterField( + model_name='modelswitch', + name='is_itself_module', + field=models.BooleanField(default=False, help_text='Is the switch, itself, considered as a module'), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index fd054c43..e05fa50e 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -251,7 +251,7 @@ class Switch(AclMixin, Machine): default=False, help_text='Provision automatique de ce switch', ) - + class Meta: unique_together = ('stack', 'stack_member_id') @@ -404,11 +404,11 @@ class ModelSwitch(AclMixin, RevMixin, models.Model): is_modular = models.BooleanField( default=False, help_text=_("Is this switch model modular"), - ) + ) is_itself_module = models.BooleanField( default=False, - help_text=_("Does the switch, itself, considered as a module"), - ) + help_text=_("Is the switch, itself, considered as a module"), + ) class Meta: permissions = ( @@ -429,14 +429,14 @@ class ModuleSwitch(AclMixin, RevMixin, models.Model): reference = models.CharField( max_length=255, help_text=_("Reference of a module"), - verbose_name=_("Module reference") + verbose_name=_("Module reference") ) comment = models.CharField( max_length=255, null=True, blank=True, help_text=_("Comment"), - verbose_name=_("Comment") + verbose_name=_("Comment") ) class Meta: @@ -457,7 +457,7 @@ class ModuleOnSwitch(AclMixin, RevMixin, models.Model): slot = models.CharField( max_length=15, help_text=_("Slot on switch"), - verbose_name=_("Slot") + verbose_name=_("Slot") ) class Meta: