8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-26 22:52:26 +00:00

Récupération de code

This commit is contained in:
grisel-davy 2018-05-21 21:13:44 +02:00
parent 7e3e27be90
commit d8f139c207
4 changed files with 287 additions and 29 deletions

View file

@ -40,7 +40,8 @@ from __future__ import unicode_literals
import itertools import itertools
from django.db import models 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.dispatch import receiver
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import IntegrityError from django.db import IntegrityError
@ -50,6 +51,11 @@ from reversion import revisions as reversion
from machines.models import Machine, regen from machines.models import Machine, regen
from re2o.mixins import AclMixin, RevMixin from re2o.mixins import AclMixin, RevMixin
from os.path import isfile
from os import remove
class Stack(AclMixin, RevMixin, models.Model): class Stack(AclMixin, RevMixin, models.Model):
"""Un objet stack. Regrouppe des switchs en foreign key """Un objet stack. Regrouppe des switchs en foreign key
@ -103,6 +109,70 @@ class AccessPoint(AclMixin, Machine):
("view_accesspoint", "Peut voir une borne"), ("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): def __str__(self):
return str(self.interface_set.first()) return str(self.interface_set.first())
@ -422,15 +492,47 @@ class Room(AclMixin, RevMixin, models.Model):
def ap_post_save(**_kwargs): def ap_post_save(**_kwargs):
"""Regeneration des noms des bornes vers le controleur""" """Regeneration des noms des bornes vers le controleur"""
regen('unifi-ap-names') regen('unifi-ap-names')
regen("graph_topo")
@receiver(post_delete, sender=AccessPoint) @receiver(post_delete, sender=AccessPoint)
def ap_post_delete(**_kwargs): def ap_post_delete(**_kwargs):
"""Regeneration des noms des bornes vers le controleur""" """Regeneration des noms des bornes vers le controleur"""
regen('unifi-ap-names') regen('unifi-ap-names')
regen("graph_topo")
@receiver(post_delete, sender=Stack) @receiver(post_delete, sender=Stack)
def stack_post_delete(**_kwargs): def stack_post_delete(**_kwargs):
"""Vide les id des switches membres d'une stack supprimée""" """Vide les id des switches membres d'une stack supprimée"""
Switch.objects.filter(stack=None).update(stack_member_id=None) 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")

View file

@ -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=<
<TABLE BGCOLOR="{{ colors.back}}" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head_bornes }}">
<FONT FACE="Helvetica Bold" COLOR="white">Borne</FONT></TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head_bornes }}">
<FONT FACE="Helvetica Bold" COLOR="white">Switch</FONT></TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head_bornes }}">
<FONT FACE="Helvetica Bold" COLOR="white">Port</FONT></TD>
</TR>
{% for borne in sub.bornes %}
<TR>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ borne.name }}</FONT>
</TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ borne.switch }}</FONT>
</TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ borne.port }}</FONT>
</TD>
</TR>
{% endfor %}
</TABLE>
>] {{sub.bat_name}}bornes;
{% endblock %}
{% endif %}
{% if sub.machines %}
{% block machines %}
node [label=<
<TABLE BGCOLOR="{{ colors.back}}" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head_server }}">
<FONT FACE="Helvetica Bold" COLOR="white">Machine</FONT></TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head_server }}">
<FONT FACE="Helvetica Bold" COLOR="white">Switch</FONT></TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head_server }}">
<FONT FACE="Helvetica Bold" COLOR="white">Port</FONT></TD>
</TR>
{% for machine in sub.machines %}
<TR>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ machine.name }}</FONT>
</TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ machine.switch }}</FONT>
</TD>
<TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ machine.port }}</FONT>
</TD>
</TR>
{% endfor %}
</TABLE>
>] {{sub.bat_name}}machines;
{% endblock %}
{% endif %}
{% block switchs %}
{% for switch in sub.switchs %}
node [label=<
<TABLE BGCOLOR="{{ colors.back }}" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head }}">
<FONT FACE="Helvetica Bold" COLOR="white">
{{ switch.name }}
</FONT></TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >Modèle</FONT>
</TD>
<TD ALIGN="LEFT">
<FONT COLOR="{{ colors.texte }}" >{{ switch.model }}</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >Taille</FONT>
</TD>
<TD ALIGN="LEFT">
<FONT COLOR="{{ colors.texte }}" >{{ switch.nombre }}</FONT>
</TD></TR>
{% block liens %}
{% for port in switch.ports %}
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="{{ colors.texte }}" >{{ port.numero }}</FONT>
</TD>
<TD ALIGN="LEFT">
<FONT COLOR="{{ colors.texte }}" >{{ port.related }}</FONT>
</TD></TR>
{% endfor %}
{% endblock %}
</TABLE>
>] "{{ switch.id }}" ;
{% endfor %}
{% endblock %}
}
{% endfor %}
{% endblock %}
{% block isoles %}
{% for switchs in alone %}
"{{switchs.id}}" [label=<
<TABLE BGCOLOR="{{ colors.back }}" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="{{ colors.head }}">
<FONT FACE="Helvetica Bold" COLOR="white">
{{switchs.name}}
</FONT></TD></TR>
</TABLE>
>]
{% endfor %}
{% endblock %}
{% block links %}
{% for link in links %}
"{{ link.depart }}" -> "{{ link.arrive }}";
{% endfor %}
{% endblock %}
}
{% endblock %}

View file

@ -29,7 +29,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block title %}Switchs{% endblock %} {% block title %}Switchs{% endblock %}
{% block content %} {% block content %}
<img id="zoom_01" src="/media/images/switchs.png" data-zoom-image="/media/images/switchs.png" width=100% />
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collImg" aria-expanded="false" aria-controls="collapse">
Topologie des Switchs
</button>
<a target="_blank" href="/media/images/switchs.png" class="btn btn-primary">
<span class="fa fa-arrows-alt"></span>
</a>
<div id="collImg">
<img id="zoom_01" src="/media/images/switchs.png" href="/media/images/switchs.png" target="_blank" data-zoom-image="/media/images/switchs.png" width=100% />
</div>
<script type="text/javascript" src="/static/js/jquery.ez-plus.js"></script> <script type="text/javascript" src="/static/js/jquery.ez-plus.js"></script>

View file

@ -45,6 +45,8 @@ from django.core.exceptions import ValidationError
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.template.loader import get_template from django.template.loader import get_template
from django.template import Context, Template, loader from django.template import Context, Template, loader
from django.db.models.signals import post_save
from django.dispatch import receiver
import pprint import pprint
@ -95,7 +97,13 @@ from .forms import (
EditBuildingForm EditBuildingForm
) )
from subprocess import Popen,PIPE from subprocess import (
Popen,
PIPE
)
from os.path import isfile
from os import remove
@login_required @login_required
@ -124,6 +132,8 @@ def index(request):
for service_link in Service_link.objects.filter(service__service_type='graph_topo'): for service_link in Service_link.objects.filter(service__service_type='graph_topo'):
service_link.done_regen() service_link.done_regen()
if not isfile("/var/www/re2o/media/images/switchs.png"):
make_machine_graph()
return render( return render(
request, request,
'topologie/index.html', 'topologie/index.html',
@ -954,7 +964,7 @@ def make_machine_graph():
'links' : [], 'links' : [],
'alone': [], 'alone': [],
'colors': { 'colors': {
'head': "#7f0505",#Color parameters for the graph 'head': "#7f0505", # Color parameters for the graph
'back': "#b5adad", 'back': "#b5adad",
'texte': "#563d01", 'texte': "#563d01",
'border_bornes': "#02078e", 'border_bornes': "#02078e",
@ -964,8 +974,8 @@ def make_machine_graph():
} }
missing = list(Switch.objects.all()) missing = list(Switch.objects.all())
detected = [] detected = []
#Visit all buildings for building in Building.objects.all(): # Visit all buildings
for building in Building.objects.all():
dico['subs'].append( dico['subs'].append(
{ {
'bat_id': building.id, 'bat_id': building.id,
@ -975,8 +985,8 @@ def make_machine_graph():
'machines': [] 'machines': []
} }
) )
#Visit all switchs in this building # Visit all switchs in this building
for switch in Switch.objects.filter(switchbay__building=building): for switch in Switch.objects.filter(switchbay__building=building):
dico['subs'][-1]['switchs'].append({ dico['subs'][-1]['switchs'].append({
'name': switch.main_interface().domain.name, 'name': switch.main_interface().domain.name,
'nombre': switch.number, 'nombre': switch.number,
@ -985,7 +995,7 @@ def make_machine_graph():
'batiment': building, 'batiment': building,
'ports': [] 'ports': []
}) })
#visit all ports of this switch and add the switchs linked to it # visit all ports of this switch and add the switchs linked to it
for port in switch.ports.filter(related__isnull=False): for port in switch.ports.filter(related__isnull=False):
dico['subs'][-1]['switchs'][-1]['ports'].append({ dico['subs'][-1]['switchs'][-1]['ports'].append({
'numero': port.port, 'numero': port.port,
@ -1007,18 +1017,18 @@ def make_machine_graph():
'port': Port.objects.filter(machine_interface__machine=server)[0].port 'port': Port.objects.filter(machine_interface__machine=server)[0].port
}) })
#While the list of forgotten ones is not empty # While the list of forgotten ones is not empty
while missing: while missing:
if missing[0].ports.count():#The switch is not empty if missing[0].ports.count(): # The switch is not empty
links, new_detected = recursive_switchs(missing[0], None, [missing[0]]) links, new_detected = recursive_switchs(missing[0], None, [missing[0]])
for link in links: for link in links:
dico['links'].append(link) dico['links'].append(link)
#Update the lists of missings and already detected switchs # Update the lists of missings and already detected switchs
missing=[i for i in missing if i not in new_detected] missing=[i for i in missing if i not in new_detected]
detected += new_detected detected += new_detected
else:#If the switch have no ports, don't explore it and hop to the next one else: # If the switch have no ports, don't explore it and hop to the next one
del missing[0] del missing[0]
#Switchs that are not connected or not in a building # Switchs that are not connected or not in a building
for switch in Switch.objects.filter(switchbay__isnull=True).exclude(ports__related__isnull=False): for switch in Switch.objects.filter(switchbay__isnull=True).exclude(ports__related__isnull=False):
dico['alone'].append({ dico['alone'].append({
'id': switch.id, 'id': switch.id,
@ -1026,21 +1036,21 @@ def make_machine_graph():
}) })
dot_data=generate_image(dico)#generate the dot file dot_data=generate_dot(dico,'topologie/graph_switch.dot') # generate the dot file
fichier = open(MEDIA_ROOT + "/images/switchs.dot","w", encoding='utf-8') fichier = open(MEDIA_ROOT + "/images/switchs.dot","w", encoding='utf-8')
fichier.write(dot_data) fichier.write(dot_data)
fichier.close() fichier.close()
unflatten = Popen(#unflatten the graph to make it look better unflatten = Popen( # unflatten the graph to make it look better
["unflatten","-l", "3", MEDIA_ROOT + "/images/switchs.dot"], ["unflatten","-l", "3", MEDIA_ROOT + "/images/switchs.dot"],
stdout=PIPE stdout=PIPE
) )
image = Popen(#pipe the result of the first command into the second image = Popen( # pipe the result of the first command into the second
["dot", "-Tpng", "-o", MEDIA_ROOT + "/images/switchs.png"], ["dot", "-Tpng", "-o", MEDIA_ROOT + "/images/switchs.png"],
stdin=unflatten.stdout, stdin=unflatten.stdout,
stdout=PIPE stdout=PIPE
) )
def generate_dot(data,template='topologie/graph_switch.dot'): def generate_dot(data,template):
"""create the dot file """create the dot file
:param data: dictionary passed to the template :param data: dictionary passed to the template
:param template: path to the dot template :param template: path to the dot template
@ -1060,19 +1070,19 @@ def recursive_switchs(switch_start, switch_before, detected):
:param switch_before: the switch that you come from. None if switch_start is the first one :param switch_before: the switch that you come from. None if switch_start is the first one
:param detected: list of all switchs already visited. None if switch_start is the first one :param detected: list of all switchs already visited. None if switch_start is the first one
:return: A list of all the links found and a list of all the switchs visited""" :return: A list of all the links found and a list of all the switchs visited"""
links_return=[]#list of dictionaries of the links to be detected links_return=[] # list of dictionaries of the links to be detected
for port in switch_start.ports.filter(related__isnull=False):#Ports that are related to another switch for port in switch_start.ports.filter(related__isnull=False): # Ports that are related to another switch
if port.related.switch != switch_before and port.related.switch != port.switch:#Not the switch that we come from, not the current switch if port.related.switch != switch_before and port.related.switch != port.switch: # Not the switch that we come from, not the current switch
links = {#Dictionary of a link links = { # Dictionary of a link
'depart':switch_start.id, 'depart':switch_start.id,
'arrive':port.related.switch.id 'arrive':port.related.switch.id
} }
if port.related.switch not in detected:#The switch at the end of this link has not been visited if port.related.switch not in detected: # The switch at the end of this link has not been visited
links_down, detected = recursive_switchs(port.related.switch, switch_start, detected)#explore it and get the results links_down, detected = recursive_switchs(port.related.switch, switch_start, detected) # explore it and get the results
for link in links_down:#Add the non empty links to the current list for link in links_down: # Add the non empty links to the current list
if link: if link:
links_return.append(link) links_return.append(link)
links_return.append(links)#Add current and below levels links links_return.append(links) # Add current and below levels links
detected.append(switch_start)#This switch is considered detected detected.append(switch_start) # This switch is considered detected
return (links_return, detected) return (links_return, detected)