diff --git a/machines/migrations/0081_auto_20180511_1254.py b/machines/migrations/0081_auto_20180511_1254.py new file mode 100644 index 00000000..8f7af9f7 --- /dev/null +++ b/machines/migrations/0081_auto_20180511_1254.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-05-11 17:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0080_auto_20180502_2334'), + ] + + operations = [ + migrations.AlterField( + model_name='service_link', + name='server', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='machines.Interface'), + ), + ] diff --git a/machines/models.py b/machines/models.py index fe1923bb..4057bb16 100644 --- a/machines/models.py +++ b/machines/models.py @@ -1373,9 +1373,8 @@ class Service(RevMixin, AclMixin, models.Model): def regen(service): """ Fonction externe pour régérération d'un service, prend un objet service en arg""" - obj = Service.objects.filter(service_type=service) - if obj: - obj[0].ask_regen() + obj, created = Service.objects.get_or_create(service_type=service) + obj.ask_regen() return @@ -1384,7 +1383,12 @@ class Service_link(RevMixin, AclMixin, models.Model): PRETTY_NAME = "Relation entre service et serveur" service = models.ForeignKey('Service', on_delete=models.CASCADE) - server = models.ForeignKey('Interface', on_delete=models.CASCADE) + server = models.ForeignKey( + 'Interface', + on_delete=models.CASCADE, + null=True, + blank=True + ) last_regen = models.DateTimeField(auto_now_add=True) asked_regen = models.BooleanField(default=False) @@ -1525,6 +1529,8 @@ def machine_post_save(**kwargs): user.ldap_sync(base=False, access_refresh=False, mac_refresh=True) regen('dhcp') regen('mac_ip_list') + if user == preferences.models.OptionalMachine.get_cached_value('utilisateur_asso'): + regen('graph_topo') @receiver(post_delete, sender=Machine) @@ -1549,6 +1555,8 @@ def interface_post_save(**kwargs): # Regen services regen('dhcp') regen('mac_ip_list') + if interface.machine.user == preferences.models.OptionalMachine.get_cached_value('utilisateur_asso'): + regen('graph_topo') @receiver(post_delete, sender=Interface) @@ -1659,3 +1667,11 @@ def srv_post_save(**_kwargs): def srv_post_delete(**_kwargs): """Regeneration dns après modification d'un SRV""" regen('dns') + + +@receiver(post_save, sender=Service) +def service_post_save(**kwargs): + """Création d'un service_link si non existant""" + service = kwargs['instance'] + service_link, created = Service_link.objects.get_or_create(service=service) + diff --git a/media/images/__init__.py b/media/images/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/re2o/mixins.py b/re2o/mixins.py index 2ee049cc..8895d099 100644 --- a/re2o/mixins.py +++ b/re2o/mixins.py @@ -24,6 +24,7 @@ A set of mixins used all over the project to avoid duplicating code """ from reversion import revisions as reversion +from django.utils.functional import cached_property from django.db import transaction @@ -161,3 +162,5 @@ class AclMixin(object): ), u"Vous n'avez pas le droit de voir des " + self.get_classname() ) + + diff --git a/topologie/migrations/0060_server.py b/topologie/migrations/0060_server.py new file mode 100644 index 00000000..802affcf --- /dev/null +++ b/topologie/migrations/0060_server.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2018-05-11 17:54 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('machines', '0081_auto_20180511_1254'), + ('topologie', '0059_auto_20180415_2249'), + ] + + operations = [ + migrations.CreateModel( + name='Server', + fields=[ + ], + options={ + 'proxy': True, + }, + bases=('machines.machine',), + ), + ] diff --git a/topologie/models.py b/topologie/models.py index 23b72b75..e1c945c7 100644 --- a/topologie/models.py +++ b/topologie/models.py @@ -40,7 +40,8 @@ from __future__ import unicode_literals import itertools from django.db import models -from django.db.models.signals import post_save, post_delete +from django.db.models.signals import pre_save, post_save, post_delete +from django.utils.functional import cached_property from django.dispatch import receiver from django.core.exceptions import ValidationError from django.db import IntegrityError @@ -50,6 +51,11 @@ from reversion import revisions as reversion from machines.models import Machine, regen from re2o.mixins import AclMixin, RevMixin +from os.path import isfile +from os import remove + + + class Stack(AclMixin, RevMixin, models.Model): """Un objet stack. Regrouppe des switchs en foreign key @@ -103,6 +109,70 @@ class AccessPoint(AclMixin, Machine): ("view_accesspoint", "Peut voir une borne"), ) + def port(self): + """Return the queryset of ports for this device""" + return Port.objects.filter( + machine_interface__machine=self + ) + + def switch(self): + """Return the switch where this is plugged""" + return Switch.objects.filter( + ports__machine_interface__machine=self + ) + + def building(self): + """Return the building of the AP/Server (building of the switchs connected to...)""" + return Building.objects.filter( + switchbay__switch=self.switch() + ) + + @cached_property + def short_name(self): + return str(self.interface_set.first().domain.name) + + @classmethod + def all_ap_in(cls, building_instance): + """Get a building as argument, returns all ap of a building""" + return cls.objects.filter(interface__port__switch__switchbay__building=building_instance) + + def __str__(self): + return str(self.interface_set.first()) + + +class Server(Machine): + """Dummy class, to retrieve servers of a building, or get switch of a server""" + + class Meta: + proxy = True + + def port(self): + """Return the queryset of ports for this device""" + return Port.objects.filter( + machine_interface__machine=self + ) + + def switch(self): + """Return the switch where this is plugged""" + return Switch.objects.filter( + ports__machine_interface__machine=self + ) + + def building(self): + """Return the building of the AP/Server (building of the switchs connected to...)""" + return Building.objects.filter( + switchbay__switch=self.switch() + ) + + @cached_property + def short_name(self): + return str(self.interface_set.first().domain.name) + + @classmethod + def all_server_in(cls, building_instance): + """Get a building as argument, returns all server of a building""" + return cls.objects.filter(interface__port__switch__switchbay__building=building_instance).exclude(accesspoint__isnull=False) + def __str__(self): return str(self.interface_set.first()) @@ -422,15 +492,47 @@ class Room(AclMixin, RevMixin, models.Model): def ap_post_save(**_kwargs): """Regeneration des noms des bornes vers le controleur""" regen('unifi-ap-names') - + regen("graph_topo") @receiver(post_delete, sender=AccessPoint) def ap_post_delete(**_kwargs): """Regeneration des noms des bornes vers le controleur""" regen('unifi-ap-names') - + regen("graph_topo") @receiver(post_delete, sender=Stack) def stack_post_delete(**_kwargs): """Vide les id des switches membres d'une stack supprimée""" Switch.objects.filter(stack=None).update(stack_member_id=None) + +@receiver(post_save, sender=Port) +def port_post_save(**_kwargs): + regen("graph_topo") + +@receiver(post_delete, sender=Port) +def port_post_delete(**_kwargs): + regen("graph_topo") + +@receiver(post_save, sender=ModelSwitch) +def modelswitch_post_save(**_kwargs): + regen("graph_topo") + +@receiver(post_delete, sender=ModelSwitch) +def modelswitch_post_delete(**_kwargs): + regen("graph_topo") + +@receiver(post_save, sender=Building) +def building_post_save(**_kwargs): + regen("graph_topo") + +@receiver(post_delete, sender=Building) +def building_post_delete(**_kwargs): + regen("graph_topo") + +@receiver(post_save, sender=Switch) +def switch_post_save(**_kwargs): + regen("graph_topo") + +@receiver(post_delete, sender=Switch) +def switch_post_delete(**_kwargs): + regen("graph_topo") diff --git a/topologie/templates/topologie/graph_switch.dot b/topologie/templates/topologie/graph_switch.dot new file mode 100644 index 00000000..46c6a766 --- /dev/null +++ b/topologie/templates/topologie/graph_switch.dot @@ -0,0 +1,135 @@ +{% block graph_dot %} +strict digraph { +graph [label="TOPOLOGIE DU RÉSEAU", labelloc=t, fontsize=40]; +node [fontname=Helvetica fontsize=8 shape=plaintext]; +edge[arrowhead=none]; + + +{% block subgraphs %} +{% for sub in subs %} +subgraph cluster_{{ sub.bat_id }} { +fontsize=15; +label="Batiment {{ sub.bat_name }}"; + +{% if sub.bornes %} +{% block bornes %} +node [label=< + + + + + + +{% for borne in sub.bornes %} + + + + + +{% endfor %} +
+ Borne + Switch + Port
+ {{ borne.name }} + + {{ borne.switch }} + + {{ borne.port }} +
+>] {{sub.bat_name}}bornes; +{% endblock %} +{% endif %} + +{% if sub.machines %} +{% block machines %} +node [label=< + + + + + + + +{% for machine in sub.machines %} + + + + + +{% endfor %} +
+ Machine + Switch + Port
+ {{ machine.name }} + + {{ machine.switch }} + + {{ machine.port }} +
+>] {{sub.bat_name}}machines; +{% endblock %} +{% endif %} + + +{% block switchs %} +{% for switch in sub.switchs %} +node [label=< + + + + + + +{% block liens %} +{% for port in switch.ports %} + + +{% endfor %} +{% endblock %} +
+ +{{ switch.name }} +
+Modèle + +{{ switch.model }} +
+Taille + +{{ switch.nombre }} +
+{{ port.numero }} + +{{ port.related }} +
+>] "{{ switch.id }}" ; +{% endfor %} +{% endblock %} +} +{% endfor %} +{% endblock %} + + +{% block isoles %} +{% for switchs in alone %} +"{{switchs.id}}" [label=< + + +
+ +{{switchs.name}} +
+>] +{% endfor %} +{% endblock %} + + +{% block links %} +{% for link in links %} +"{{ link.depart }}" -> "{{ link.arrive }}"; +{% endfor %} +{% endblock %} +} +{% endblock %} \ No newline at end of file diff --git a/topologie/templates/topologie/index.html b/topologie/templates/topologie/index.html index 6e140251..a69d87d0 100644 --- a/topologie/templates/topologie/index.html +++ b/topologie/templates/topologie/index.html @@ -29,10 +29,17 @@ with this program; if not, write to the Free Software Foundation, Inc., {% block title %}Switchs{% endblock %} {% block content %} + + + + +
+
-