8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-22 23:13:46 +00:00

Add or translate some docstrings in topologie/

This commit is contained in:
Laouen Fernet 2020-04-29 15:00:47 +02:00 committed by Gabriel Detraz
parent d186449767
commit 7939a986d0
4 changed files with 363 additions and 264 deletions

View file

@ -20,8 +20,8 @@
# 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.
"""
Fichier définissant les administration des models dans l'interface admin
"""topologie.admin
The objects, fields and datastructures visible in the Django admin view.
"""
from __future__ import unicode_literals
@ -45,67 +45,67 @@ from .models import (
class StackAdmin(VersionAdmin):
"""Administration d'une stack de switches (inclus des switches)"""
"""Admin class of stacks (includes switches)."""
pass
class SwitchAdmin(VersionAdmin):
"""Administration d'un switch"""
"""Admin class of switches."""
pass
class PortAdmin(VersionAdmin):
"""Administration d'un port de switches"""
"""Admin class of switch ports."""
pass
class AccessPointAdmin(VersionAdmin):
"""Administration d'une borne"""
"""Admin class of APs."""
pass
class RoomAdmin(VersionAdmin):
"""Administration d'un chambre"""
"""Admin class of rooms."""
pass
class ModelSwitchAdmin(VersionAdmin):
"""Administration d'un modèle de switch"""
"""Admin class of switch models."""
pass
class ConstructorSwitchAdmin(VersionAdmin):
"""Administration d'un constructeur d'un switch"""
"""Admin class of switch constructors."""
pass
class SwitchBayAdmin(VersionAdmin):
"""Administration d'une baie de brassage"""
"""Admin class of switch bays."""
pass
class BuildingAdmin(VersionAdmin):
"""Administration d'un batiment"""
"""Admin class of buildings."""
pass
class DormitoryAdmin(VersionAdmin):
"""Administration d'une residence"""
"""Admin class of dormitories."""
pass
class PortProfileAdmin(VersionAdmin):
"""Administration of a port profile"""
"""Admin class of port profiles."""
pass

View file

@ -20,14 +20,12 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Un forms le plus simple possible pour les objets topologie de re2o.
Forms for the topologie app of re2o.
Permet de créer et supprimer : un Port de switch, relié à un switch.
Permet de créer des stacks et d'y ajouter des switchs (StackForm)
Permet de créer, supprimer et editer un switch (EditSwitchForm,
NewSwitchForm)
The forms are used to:
* create and delete switch ports, related to a switch.
* create stacks and add switches to them (StackForm).
* create, edit and delete a switch (NewSwitchForm, EditSwitchForm).
"""
from __future__ import unicode_literals
@ -59,8 +57,7 @@ from .models import (
class PortForm(FormRevMixin, ModelForm):
"""Formulaire pour la création d'un port d'un switch
Relié directement au modèle port"""
"""Form used to manage a switch's port."""
class Meta:
model = Port
@ -72,14 +69,11 @@ class PortForm(FormRevMixin, ModelForm):
class EditPortForm(FormRevMixin, ModelForm):
"""Form pour l'édition d'un port de switche : changement des reglages
radius ou vlan, ou attribution d'une chambre, autre port ou machine
"""Form used to edit a switch's port: change in RADIUS or VLANs settings,
assignement to a room, port or machine.
Un port est relié à une chambre, un autre port (uplink) ou une machine
(serveur ou borne), mutuellement exclusif
Optimisation sur les queryset pour machines et port_related pour
optimiser le temps de chargement avec select_related (vraiment
lent sans)"""
A port is related to either a room, another port (uplink) or a machine (server or AP).
"""
class Meta(PortForm.Meta):
fields = [
@ -106,8 +100,7 @@ class EditPortForm(FormRevMixin, ModelForm):
class AddPortForm(FormRevMixin, ModelForm):
"""Permet d'ajouter un port de switch. Voir EditPortForm pour plus
d'informations"""
"""Form used to add a switch's port. See EditPortForm."""
class Meta(PortForm.Meta):
fields = [
@ -139,8 +132,7 @@ class AddPortForm(FormRevMixin, ModelForm):
class StackForm(FormRevMixin, ModelForm):
"""Permet d'edition d'une stack : stack_id, et switches membres
de la stack"""
"""Form used to create and edit stacks."""
class Meta:
model = Stack
@ -152,8 +144,7 @@ class StackForm(FormRevMixin, ModelForm):
class AddAccessPointForm(NewMachineForm):
"""Formulaire pour la création d'une borne
Relié directement au modèle borne"""
"""Form used to create access points."""
class Meta:
model = AccessPoint
@ -161,7 +152,7 @@ class AddAccessPointForm(NewMachineForm):
class EditAccessPointForm(EditMachineForm):
"""Edition d'une borne. Edition complète"""
"""Form used to edit access points."""
class Meta:
model = AccessPoint
@ -169,7 +160,7 @@ class EditAccessPointForm(EditMachineForm):
class EditSwitchForm(EditMachineForm):
"""Permet d'éditer un switch : nom et nombre de ports"""
"""Form used to edit switches."""
class Meta:
model = Switch
@ -177,15 +168,14 @@ class EditSwitchForm(EditMachineForm):
class NewSwitchForm(NewMachineForm):
"""Permet de créer un switch : emplacement, paramètres machine,
membre d'un stack (option), nombre de ports (number)"""
"""Form used to create a switch."""
class Meta(EditSwitchForm.Meta):
fields = ["name", "switchbay", "number", "stack", "stack_member_id"]
class EditRoomForm(FormRevMixin, ModelForm):
"""Permet d'éediter le nom et commentaire d'une prise murale"""
"""Form used to edit a room."""
class Meta:
model = Room
@ -197,14 +187,14 @@ class EditRoomForm(FormRevMixin, ModelForm):
class CreatePortsForm(forms.Form):
"""Permet de créer une liste de ports pour un switch."""
"""Form used to create switch ports lists."""
begin = forms.IntegerField(label=_("Start:"), min_value=0)
end = forms.IntegerField(label=_("End:"), min_value=0)
class EditModelSwitchForm(FormRevMixin, ModelForm):
"""Permet d'éediter un modèle de switch : nom et constructeur"""
"""Form used to edit switch models."""
members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False)
@ -226,7 +216,7 @@ class EditModelSwitchForm(FormRevMixin, ModelForm):
class EditConstructorSwitchForm(FormRevMixin, ModelForm):
"""Permet d'éediter le nom d'un constructeur"""
"""Form used to edit switch constructors."""
class Meta:
model = ConstructorSwitch
@ -238,7 +228,7 @@ class EditConstructorSwitchForm(FormRevMixin, ModelForm):
class EditSwitchBayForm(FormRevMixin, ModelForm):
"""Permet d'éditer une baie de brassage"""
"""Form used to edit switch bays."""
members = forms.ModelMultipleChoiceField(Switch.objects.all(), required=False)
@ -260,7 +250,7 @@ class EditSwitchBayForm(FormRevMixin, ModelForm):
class EditBuildingForm(FormRevMixin, ModelForm):
"""Permet d'éditer le batiment"""
"""Form used to edit buildings."""
class Meta:
model = Building
@ -272,7 +262,7 @@ class EditBuildingForm(FormRevMixin, ModelForm):
class EditDormitoryForm(FormRevMixin, ModelForm):
"""Enable dormitory edition"""
"""Form used to edit dormitories."""
class Meta:
model = Dormitory
@ -284,7 +274,7 @@ class EditDormitoryForm(FormRevMixin, ModelForm):
class EditPortProfileForm(FormRevMixin, ModelForm):
"""Form to edit a port profile"""
"""Form used to edit port profiles."""
class Meta:
model = PortProfile
@ -296,7 +286,7 @@ class EditPortProfileForm(FormRevMixin, ModelForm):
class EditModuleForm(FormRevMixin, ModelForm):
"""Add and edit module instance"""
"""Form used to add and edit switch modules."""
class Meta:
model = ModuleSwitch
@ -308,7 +298,7 @@ class EditModuleForm(FormRevMixin, ModelForm):
class EditSwitchModuleForm(FormRevMixin, ModelForm):
"""Add/edit a switch to a module"""
"""Form used to add and edit modules related to a switch."""
class Meta:
model = ModuleOnSwitch

View file

@ -21,18 +21,15 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Definition des modèles de l'application topologie.
Definition of models for the 'topologie' app.
On défini les models suivants :
- stack (id, id_min, id_max et nom) regrouppant les switches
- switch : nom, nombre de port, et interface
machine correspondante (mac, ip, etc) (voir machines.models.interface)
- Port: relié à un switch parent par foreign_key, numero du port,
relié de façon exclusive à un autre port, une machine
(serveur ou borne) ou une prise murale
- room : liste des prises murales, nom et commentaire de l'état de
la prise
The following models are defined:
* stack (grouping switches): id, id_min, id_max and name
* switch: name, number of ports, related interface and machine (MAC
address, IP address etc.) (see machines.models.interface)
* port: related to a switch by foreign_key, number of the port, related
exclusively to another port, machine (server or AP) or room outlets
* room: list of outlets, name and comments about the plug's state
"""
from __future__ import unicode_literals
@ -56,9 +53,15 @@ from re2o.mixins import AclMixin, RevMixin
class Stack(AclMixin, RevMixin, models.Model):
"""Un objet stack. Regrouppe des switchs en foreign key
,contient une id de stack, un switch id min et max dans
le stack"""
"""Switch stack.
Attributes:
name: the name of the stack.
stack_id: the ID of the stack, as a text chosen by the user.
details: the description to provide details about the stack.
member_id_min: the minimum switch ID in the stack.
member_id_max: the maximum switch ID in the stack.
"""
name = models.CharField(max_length=32, blank=True, null=True)
stack_id = models.CharField(max_length=32, unique=True)
@ -89,9 +92,10 @@ class Stack(AclMixin, RevMixin, models.Model):
class AccessPoint(Machine):
"""Define a wireless AP. Inherit from machines.interfaces
"""Wireless Access Point. Inherits from machines.interfaces.
Definition pour une borne wifi , hérite de machines.interfaces
Attributes:
location: the text to provide details about the AP's location.
"""
location = models.CharField(
@ -107,17 +111,16 @@ class AccessPoint(Machine):
verbose_name_plural = _("access points")
def port(self):
"""Return the queryset of ports for this device"""
"""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 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 the building of the AP/Server (building of the switches
connected to...).
"""
return Building.objects.filter(switchbay__switch=self.switch())
@ -127,7 +130,14 @@ class AccessPoint(Machine):
@classmethod
def all_ap_in(cls, building_instance):
"""Get a building as argument, returns all ap of a building"""
"""Get all the APs of the given building.
Args:
building_instance: the building used to find APs.
Returns:
The queryset of all APs in the given building.
"""
return cls.objects.filter(
interface__port__switch__switchbay__building=building_instance
)
@ -158,25 +168,24 @@ class AccessPoint(Machine):
class Server(Machine):
"""
Dummy class, to retrieve servers of a building, or get switch of a server
"""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 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 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 the building of the AP/Server (building of the switches
connected to...).
"""
return Building.objects.filter(switchbay__switch=self.switch())
@ -186,7 +195,14 @@ class Server(Machine):
@classmethod
def all_server_in(cls, building_instance):
"""Get a building as argument, returns all server of a building"""
"""Get all the servers of the given building.
Args:
building_instance: the building used to find servers.
Returns:
The queryset of all servers in the given building.
"""
return cls.objects.filter(
interface__port__switch__switchbay__building=building_instance
).exclude(accesspoint__isnull=False)
@ -217,17 +233,19 @@ class Server(Machine):
class Switch(Machine):
""" Definition d'un switch. Contient un nombre de ports (number),
un emplacement (location), un stack parent (optionnel, stack)
et un id de membre dans le stack (stack_member_id)
relié en onetoone à une interface
Pourquoi ne pas avoir fait hériter switch de interface ?
Principalement par méconnaissance de la puissance de cette façon de faire.
Ceci étant entendu, django crée en interne un onetoone, ce qui a un
effet identique avec ce que l'on fait ici
"""Switch.
Validation au save que l'id du stack est bien dans le range id_min
id_max de la stack parente"""
Attributes:
number: the number of ports of the switch.
stack: the stack the switch is a part of.
stack_member_id: the ID of the switch in the related stack.
model: the model of the switch.
switchbay: the bay in which the switch is located.
radius_key: the RADIUS key of the switch.
management_creds: the management credentials of the switch.
automatic_provision: whether automatic provision is enabled for the
switch.
"""
number = models.PositiveIntegerField(help_text=_("Number of ports."))
stack = models.ForeignKey(
@ -269,8 +287,9 @@ class Switch(Machine):
verbose_name_plural = _("switches")
def clean(self):
""" Verifie que l'id stack est dans le bon range
Appelle également le clean de la classe parente"""
"""Check if the stack member ID is in the range of the stack's IDs and
calls the clean of the parent class.
"""
super(Switch, self).clean()
if self.stack is not None:
if self.stack_member_id is not None:
@ -293,6 +312,12 @@ class Switch(Machine):
def create_ports(self, begin, end):
""" Crée les ports de begin à end si les valeurs données
sont cohérentes. """
"""Create ports for the switch if the values are consistent.
Args:
begin: the number of the start port.
end: the number of the end port.
"""
if end < begin:
raise ValidationError(_("The end port is less than the start port."))
ports_to_create = range(begin, end + 1)
@ -313,8 +338,7 @@ class Switch(Machine):
)
def main_interface(self):
""" Returns the 'main' interface of the switch
It must the the management interface for that device"""
"""Get the main interface of the switch (the management interface)."""
switch_iptype = OptionalTopologie.get_cached_value("switchs_ip_type")
if switch_iptype:
return (
@ -329,12 +353,14 @@ class Switch(Machine):
@cached_property
def get_radius_key(self):
"""Retourne l'objet de la clef radius de ce switch"""
"""Get the RADIUS key object related to the switch."""
return self.radius_key or RadiusKey.objects.filter(default_switch=True).first()
@cached_property
def get_radius_key_value(self):
"""Retourne la valeur en str de la clef radius, none si il n'y en a pas"""
"""Get the RADIUS key as a string, or None if there are no RADIUS key
related to the switch.
"""
if self.get_radius_key:
return self.get_radius_key.radius_key
else:
@ -362,7 +388,7 @@ class Switch(Machine):
@cached_property
def get_management_cred(self):
"""Retourne l'objet des creds de managament de ce switch"""
"""Get the management credentials objects of the switch."""
return (
self.management_creds
or SwitchManagementCred.objects.filter(default_switch=True).first()
@ -370,7 +396,9 @@ class Switch(Machine):
@cached_property
def get_management_cred_value(self):
"""Retourne un dict des creds de management du switch"""
"""Get the management credentials as a dictionary, or None if there are
no management credentials related to the switch.
"""
if self.get_management_cred:
return {
"id": self.get_management_cred.management_id,
@ -401,17 +429,19 @@ class Switch(Machine):
@cached_property
def ipv4(self):
"""Return the switch's management ipv4"""
"""Get the IPv4 address of the switch's management interface."""
return str(self.main_interface().ipv4)
@cached_property
def ipv6(self):
"""Returne the switch's management ipv6"""
"""Get the IPv6 address of the switch's management interface."""
return str(self.main_interface().ipv6().first())
@cached_property
def interfaces_subnet(self):
"""Return dict ip:subnet for all ip of the switch"""
"""Get a dictionary of IPv4 addresses:subnets of all the switch's
interfaces.
"""
return dict(
(
str(interface.ipv4),
@ -423,7 +453,9 @@ class Switch(Machine):
@cached_property
def interfaces6_subnet(self):
"""Return dict ip6:subnet for all ipv6 of the switch"""
"""Get a dictionary of IPv6 addresses:subnets of all the switch's
interfaces.
"""
return dict(
(
str(interface.ipv6().first()),
@ -434,7 +466,9 @@ class Switch(Machine):
@cached_property
def list_modules(self):
"""Return modules of that switch, list of dict (rank, reference)"""
"""Get the list of dictionaries (rank, reference) of modules related to
the switch.
"""
modules = []
if getattr(self.model, "is_modular", None):
if self.model.is_itself_module:
@ -445,7 +479,7 @@ class Switch(Machine):
@cached_property
def get_dormitory(self):
"""Returns the dormitory of that switch"""
"""Get the dormitory in which the switch is located."""
if self.switchbay:
return self.switchbay.building.dormitory
else:
@ -453,19 +487,19 @@ class Switch(Machine):
@classmethod
def nothing_profile(cls):
"""Return default nothing port profile"""
"""Return default nothing port profile."""
nothing_profile, _created = PortProfile.objects.get_or_create(
profil_default="nothing", name="nothing", radius_type="NO"
)
return nothing_profile
def profile_type_or_nothing(self, profile_type):
"""Return the profile for a profile_type of this switch
"""Return the profile for a profile_type of this switch.
If exists, returns the defined default profile for a profile type on the dormitory which
the switch belongs
Otherwise, returns the nothing profile"""
If it exists, return the defined default profile for a profile type on
the dormitory which the switch belongs.
Otherwise, return the nothing profile.
"""
profile_queryset = PortProfile.objects.filter(profil_default=profile_type)
if self.get_dormitory:
port_profile = (
@ -478,22 +512,22 @@ class Switch(Machine):
@cached_property
def default_uplink_profile(self):
"""Default uplink profile for that switch -- in cache"""
"""Default uplink profile for that switch -- in cache."""
return self.profile_type_or_nothing("uplink")
@cached_property
def default_access_point_profile(self):
"""Default ap profile for that switch -- in cache"""
"""Default AP profile for that switch -- in cache."""
return self.profile_type_or_nothing("access_point")
@cached_property
def default_room_profile(self):
"""Default room profile for that switch -- in cache"""
"""Default room profile for that switch -- in cache."""
return self.profile_type_or_nothing("room")
@cached_property
def default_asso_machine_profile(self):
"""Default asso machine profile for that switch -- in cache"""
"""Default asso machine profile for that switch -- in cache."""
return self.profile_type_or_nothing("asso_machine")
def __str__(self):
@ -522,7 +556,16 @@ class Switch(Machine):
class ModelSwitch(AclMixin, RevMixin, models.Model):
"""Un modèle (au sens constructeur) de switch"""
"""Switch model.
Attributes:
reference: the reference of the switch model.
commercial_name: the commercial name of the switch model.
constructor: the constructor of the switch model.
firmware: the firmware of the switch model.
is_modular: whether the switch model is modular.
is_itself_module: whether the switch is considered as a module.
"""
reference = models.CharField(max_length=255)
commercial_name = models.CharField(max_length=255, null=True, blank=True)
@ -550,7 +593,12 @@ class ModelSwitch(AclMixin, RevMixin, models.Model):
class ModuleSwitch(AclMixin, RevMixin, models.Model):
"""A module of a switch"""
"""Switch module.
Attributes:
reference: the reference of the switch module.
comment: the comment to describe the switch module.
"""
reference = models.CharField(
max_length=255,
@ -575,7 +623,13 @@ class ModuleSwitch(AclMixin, RevMixin, models.Model):
class ModuleOnSwitch(AclMixin, RevMixin, models.Model):
"""Link beetween module and switch"""
"""Link beetween module and switch.
Attributes:
module: the switch module related to the link.
switch: the switch related to the link.
slot: the slot on the switch related to the link.
"""
module = models.ForeignKey("ModuleSwitch", on_delete=models.CASCADE)
switch = models.ForeignKey("Switch", on_delete=models.CASCADE)
@ -601,7 +655,11 @@ class ModuleOnSwitch(AclMixin, RevMixin, models.Model):
class ConstructorSwitch(AclMixin, RevMixin, models.Model):
"""Un constructeur de switch"""
"""Switch constructor.
Attributes:
name: the name of the switch constructor.
"""
name = models.CharField(max_length=255)
@ -617,7 +675,13 @@ class ConstructorSwitch(AclMixin, RevMixin, models.Model):
class SwitchBay(AclMixin, RevMixin, models.Model):
"""Une baie de brassage"""
"""Switch bay.
Attributes:
name: the name of the switch bay.
building: the building in which the switch bay is located.
info: the information to describe to switch bay.
"""
name = models.CharField(max_length=255)
building = models.ForeignKey("Building", on_delete=models.PROTECT)
@ -633,8 +697,11 @@ class SwitchBay(AclMixin, RevMixin, models.Model):
class Dormitory(AclMixin, RevMixin, models.Model):
"""A student accomodation/dormitory
Une résidence universitaire"""
"""Dormitory.
Attributes:
name: the name of the dormitory.
"""
name = models.CharField(max_length=255)
@ -644,7 +711,7 @@ class Dormitory(AclMixin, RevMixin, models.Model):
verbose_name_plural = _("dormitories")
def all_ap_in(self):
"""Returns all ap of the dorms"""
"""Get all the APs in the dormitory."""
return AccessPoint.all_ap_in(self.building_set.all())
@classmethod
@ -660,8 +727,13 @@ class Dormitory(AclMixin, RevMixin, models.Model):
class Building(AclMixin, RevMixin, models.Model):
"""A building of a dormitory
Un batiment"""
"""Building.
Attributes:
name: the name of the building.
dormitory: the dormitory of the building (a Dormitory can contain
multiple dormitories).
"""
name = models.CharField(max_length=255)
dormitory = models.ForeignKey("Dormitory", on_delete=models.PROTECT)
@ -672,7 +744,7 @@ class Building(AclMixin, RevMixin, models.Model):
verbose_name_plural = _("buildings")
def all_ap_in(self):
"""Returns all ap of the building"""
"""Get all the APs in the building."""
return AccessPoint.all_ap_in(self)
def get_name(self):
@ -690,21 +762,32 @@ class Building(AclMixin, RevMixin, models.Model):
class Port(AclMixin, RevMixin, models.Model):
""" Definition d'un port. Relié à un switch(foreign_key),
un port peut etre relié de manière exclusive à :
- une chambre (room)
- une machine (serveur etc) (machine_interface)
- un autre port (uplink) (related)
Champs supplémentaires :
- RADIUS (mode STRICT : connexion sur port uniquement si machine
d'un adhérent à jour de cotisation et que la chambre est également à
jour de cotisation
mode COMMON : vérification uniquement du statut de la machine
mode NO : accepte toute demande venant du port et place sur le vlan normal
mode BLOQ : rejet de toute authentification
- vlan_force : override la politique générale de placement vlan, permet
de forcer un port sur un vlan particulier. S'additionne à la politique
RADIUS"""
"""Port of a switch.
A port is related exclusively to either:
* a room
* a machine, e.g. server
* another port
Behaviour according to the RADIUS mode:
* STRICT: connection only if the machine and room have access
* COMMON: check only the machine's state
* NO: accept only request coming from the port and set on the standard
VLAN.
* BLOQ: reject all requests.
The VLAN can be forced to override the general policy for VLAN setting.
This enables to force a port to a particular VLAN. It adds to the RADIUS
policy.
Attributes:
switch: the switch to which the port belongs.
port: the port number on the switch for the Port object.
room: the room to which the port is related.
machine_interface: the machine to which the port is related
related: the other port to which is port is related.
custom_profile: the port profile of the port.
state: whether the port is active.
details: the details to describre the port.
"""
switch = models.ForeignKey("Switch", related_name="ports", on_delete=models.CASCADE)
port = models.PositiveIntegerField()
@ -733,7 +816,7 @@ class Port(AclMixin, RevMixin, models.Model):
@cached_property
def pretty_name(self):
"""More elaborated name for label on switch conf"""
"""More elaborated name for label on switch configuration."""
if self.related:
return _("Uplink: ") + self.related.switch.short_name
elif self.machine_interface:
@ -745,14 +828,13 @@ class Port(AclMixin, RevMixin, models.Model):
@cached_property
def get_port_profile(self):
"""Return the config profil for this port
:returns: the profile of self (port)
If is defined a custom profile, returns it
elIf a default profile is defined for its dormitory, returns it
Else, returns the global default profil
If not exists, create a nothing profile"""
"""Get the configuration profile for this port.
Returns:
The custom profile if it exists, else the default profile of the
dormitory if it exists, else the global default profile, else the
nothing profile.
"""
if self.custom_profile:
return self.custom_profile
elif self.related:
@ -779,26 +861,25 @@ class Port(AclMixin, RevMixin, models.Model):
)
def make_port_related(self):
""" Synchronise le port distant sur self"""
"""Synchronise the related port with self."""
related_port = self.related
related_port.related = self
related_port.save()
def clean_port_related(self):
""" Supprime la relation related sur self"""
"""Delete the related relation on self."""
related_port = self.related_port
related_port.related = None
related_port.save()
def clean(self):
""" Verifie que un seul de chambre, interface_parent et related_port
est rempli. Verifie que le related n'est pas le port lui-même....
Verifie que le related n'est pas déjà occupé par une machine ou une
chambre. Si ce n'est pas le cas, applique la relation related
Si un port related point vers self, on nettoie la relation
A priori pas d'autre solution que de faire ça à la main. A priori
tout cela est dans un bloc transaction, donc pas de problème de
cohérence"""
"""
Check if the port is only related exclusively to either a room, a
machine or another port.
Check if the related port is not self and applies the relation to the
related port if the relation is correct.
Delete the relation if it points to self.
"""
if hasattr(self, "switch"):
if self.port > self.switch.number:
raise ValidationError(
@ -835,7 +916,13 @@ class Port(AclMixin, RevMixin, models.Model):
class Room(AclMixin, RevMixin, models.Model):
"""Une chambre/local contenant une prise murale"""
"""Room.
Attributes:
name: the name of the room.
details: the details describing the room.
building: the building in which the room is located.
"""
name = models.CharField(max_length=255)
details = models.CharField(max_length=255, blank=True)
@ -853,7 +940,28 @@ class Room(AclMixin, RevMixin, models.Model):
class PortProfile(AclMixin, RevMixin, models.Model):
"""Contains the information of the ports' configuration for a switch"""
"""Port profile.
Contains the information of the ports' configuration for a switch.
Attributes:
name: the name of the port profile.
profil_default: the type of default profile (room, AP, uplink etc.).
on_dormitory: the dormitory with this default port profile.
vlan_untagged: the VLAN untagged of the port profile.
vlan_tagged: the VLAN(s) tagged of the port profile.
radius_type: the type of RADIUS authentication (inactive, MAC-address
or 802.1X) of the port profile.
radius_mode: the RADIUS mode of the port profile.
speed: the port speed limit of the port profile.
mac_limit: the MAC limit of the port profile.
flow_control: whether flow control is enabled.
dhcp_snooping: whether DHCP snooping is enabled.
dhcpv6_snooping: whether DHCPv6 snooping is enabled.
arp_protect: whether ARP protection is enabled.
ra_guard: whether RA guard is enabled.
loop_protect: whether loop protection is enabled.
"""
TYPES = (("NO", "NO"), ("802.1X", "802.1X"), ("MAC-radius", _("MAC-RADIUS")))
MODES = (("STRICT", "STRICT"), ("COMMON", "COMMON"))
@ -983,7 +1091,7 @@ class PortProfile(AclMixin, RevMixin, models.Model):
return ",".join(self.security_parameters_enabled)
def clean(self):
""" Check that there is only one generic profil default"""
"""Check that there is only one generic profile default."""
super(PortProfile, self).clean()
if (
self.profil_default
@ -1007,21 +1115,21 @@ class PortProfile(AclMixin, RevMixin, models.Model):
@receiver(post_save, sender=AccessPoint)
def ap_post_save(**_kwargs):
"""Regeneration des noms des bornes vers le controleur"""
"""Regenerate the AP names towards the controller."""
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"""
"""Regenerate the AP names towards the controller."""
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"""
"""Empty the stack member ID of switches when a stack is deleted."""
Switch.objects.filter(stack=None).update(stack_member_id=None)

View file

@ -20,18 +20,17 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Page des vues de l'application topologie
Views for the 'topologie' app of re2o.
Permet de créer, modifier et supprimer :
- un port (add_port, edit_port, del_port)
- un switch : les vues d'ajout et d'édition font appel aux forms de creation
de switch, mais aussi aux forms de machines.forms (domain, interface et
machine). Le views les envoie et les save en même temps. TODO : rationaliser
et faire que la creation de machines (interfaces, domain etc) soit gérée
coté models et forms de topologie
- une chambre (new_room, edit_room, del_room)
- une stack
- l'historique de tous les objets cités
They are used to create, edit and delete:
* a port (add_port, edit_port, del_port)
* a switch: the views call forms for switches but also machines (domain,
interface and machine), send and save them at the same time.
TODO rationalise, enforce the creation of machines (interfaces, domains
etc.) in models and forms from 'topologie'
* a room (new_room, edit_room, del_room)
* a stack
* histories of all objects mentioned.
"""
from __future__ import unicode_literals
@ -105,7 +104,7 @@ from os.path import isfile
@login_required
@can_view_all(Switch)
def index(request):
""" Vue d'affichage de tous les swicthes"""
"""View used to display all switches."""
switch_list = (
Switch.objects.prefetch_related(
Prefetch(
@ -171,7 +170,7 @@ def index_port_profile(request):
@can_view_all(Port)
@can_view(Switch)
def index_port(request, switch, switchid):
""" Affichage de l'ensemble des ports reliés à un switch particulier"""
"""View used to display all ports related to the given switch."""
port_list = (
Port.objects.filter(switch=switch)
.select_related("room__building__dormitory")
@ -204,7 +203,7 @@ def index_port(request, switch, switchid):
@login_required
@can_view_all(Room)
def index_room(request):
""" Affichage de l'ensemble des chambres"""
"""View used to display all rooms."""
room_list = Room.objects.select_related("building__dormitory")
room_list = SortTable.sort(
room_list,
@ -220,7 +219,7 @@ def index_room(request):
@login_required
@can_view_all(AccessPoint)
def index_ap(request):
""" Affichage de l'ensemble des bornes"""
"""View used to display all APs."""
ap_list = AccessPoint.objects.prefetch_related(
Prefetch(
"interface_set",
@ -245,7 +244,7 @@ def index_ap(request):
@login_required
@can_view_all(Stack, Building, Dormitory, SwitchBay)
def index_physical_grouping(request):
"""Affichage de la liste des stacks (affiche l'ensemble des switches)"""
"""View used to display the list of stacks (display all switches)."""
stack_list = Stack.objects.prefetch_related(
"switch_set__interface_set__domain__extension"
)
@ -293,7 +292,7 @@ def index_physical_grouping(request):
@login_required
@can_view_all(ModelSwitch, ConstructorSwitch)
def index_model_switch(request):
""" Affichage de l'ensemble des modèles de switches"""
"""View used to display all switch models."""
model_switch_list = ModelSwitch.objects.select_related(
"constructor"
).prefetch_related("switch_set__interface_set__domain")
@ -323,7 +322,7 @@ def index_model_switch(request):
@login_required
@can_view_all(ModuleSwitch)
def index_module(request):
"""Display all modules of switchs"""
"""View used to display all switch modules."""
module_list = ModuleSwitch.objects.all()
modular_switchs = (
Switch.objects.filter(model__is_modular=True)
@ -342,7 +341,7 @@ def index_module(request):
@login_required
@can_edit(Vlan)
def edit_vlanoptions(request, vlan_instance, **_kwargs):
""" View used to edit options for switch of VLAN object """
"""View used to edit options for switch of VLAN object."""
vlan = EditOptionVlanForm(request.POST or None, instance=vlan_instance)
if vlan.is_valid():
if vlan.changed_data:
@ -357,7 +356,7 @@ def edit_vlanoptions(request, vlan_instance, **_kwargs):
@login_required
@can_create(Port)
def new_port(request, switchid):
""" Nouveau port"""
"""View used to create ports."""
try:
switch = Switch.objects.get(pk=switchid)
except Switch.DoesNotExist:
@ -383,9 +382,10 @@ def new_port(request, switchid):
@login_required
@can_edit(Port)
def edit_port(request, port_object, **_kwargs):
""" Edition d'un port. Permet de changer le switch parent et
l'affectation du port"""
"""View used to edit ports.
It enables to change the related switch and the port assignment.
"""
port = EditPortForm(request.POST or None, instance=port_object)
if port.is_valid():
if port.changed_data:
@ -410,7 +410,7 @@ def edit_port(request, port_object, **_kwargs):
@login_required
@can_delete(Port)
def del_port(request, port, **_kwargs):
""" Supprime le port"""
"""View used to delete ports."""
if request.method == "POST":
try:
port.delete()
@ -435,7 +435,7 @@ def del_port(request, port, **_kwargs):
@login_required
@can_create(Stack)
def new_stack(request):
"""Ajoute un nouveau stack : stackid_min, max, et nombre de switches"""
"""View used to create stacks."""
stack = StackForm(request.POST or None)
if stack.is_valid():
stack.save()
@ -449,7 +449,7 @@ def new_stack(request):
@login_required
@can_edit(Stack)
def edit_stack(request, stack, **_kwargs):
"""Edition d'un stack (nombre de switches, nom...)"""
"""View used to edit stacks."""
stack = StackForm(request.POST or None, instance=stack)
if stack.is_valid():
if stack.changed_data:
@ -464,7 +464,7 @@ def edit_stack(request, stack, **_kwargs):
@login_required
@can_delete(Stack)
def del_stack(request, stack, **_kwargs):
"""Supprime un stack"""
"""View used to delete stacks."""
if request.method == "POST":
try:
stack.delete()
@ -487,8 +487,7 @@ def del_stack(request, stack, **_kwargs):
@login_required
@can_edit(Stack)
def edit_switchs_stack(request, stack, **_kwargs):
"""Permet d'éditer la liste des switches dans une stack et l'ajouter"""
"""View used to edit the list of switches of the given stack."""
if request.method == "POST":
pass
else:
@ -500,9 +499,12 @@ def edit_switchs_stack(request, stack, **_kwargs):
@login_required
@can_create(Switch)
def new_switch(request):
""" Creation d'un switch. Cree en meme temps l'interface et la machine
associée. Vue complexe. Appelle successivement les 4 models forms
adaptés : machine, interface, domain et switch"""
"""View used to create switches.
At the same time, it creates the related interface and machine. The view
successively calls the 4 appropriate forms: machine, interface, domain and
switch.
"""
switch = NewSwitchForm(request.POST or None, user=request.user)
interface = AddInterfaceForm(request.POST or None, user=request.user)
domain = DomainForm(request.POST or None, user=request.user)
@ -549,7 +551,7 @@ def new_switch(request):
@login_required
@can_create(Port)
def create_ports(request, switchid):
""" Création d'une liste de ports pour un switch."""
"""View used to create port lists for the given switch."""
try:
switch = Switch.objects.get(pk=switchid)
except Switch.DoesNotExist:
@ -578,9 +580,11 @@ def create_ports(request, switchid):
@login_required
@can_edit(Switch)
def edit_switch(request, switch, switchid):
""" Edition d'un switch. Permet de chambre nombre de ports,
place dans le stack, interface et machine associée"""
"""View used to edit switches.
It enables to change the number of ports, location in the stack, or the
related interface and machine.
"""
switch_form = EditSwitchForm(
request.POST or None, instance=switch, user=request.user
)
@ -622,9 +626,11 @@ def edit_switch(request, switch, switchid):
@login_required
@can_create(AccessPoint)
def new_ap(request):
""" Creation d'une ap. Cree en meme temps l'interface et la machine
associée. Vue complexe. Appelle successivement les 3 models forms
adaptés : machine, interface, domain et switch"""
"""View used to create APs.
At the same time, it creates the related interface and machine. The view
successively calls the 3 appropriate forms: machine, interface, domain.
"""
ap = AddAccessPointForm(request.POST or None, user=request.user)
interface = AddInterfaceForm(request.POST or None, user=request.user)
domain = DomainForm(request.POST or None, user=request.user)
@ -671,8 +677,7 @@ def new_ap(request):
@login_required
@can_edit(AccessPoint)
def edit_ap(request, ap, **_kwargs):
""" Edition d'un switch. Permet de chambre nombre de ports,
place dans le stack, interface et machine associée"""
"""View used to edit APs."""
interface_form = EditInterfaceForm(
request.POST or None, user=request.user, instance=ap.interface_set.first()
)
@ -723,7 +728,7 @@ def edit_ap(request, ap, **_kwargs):
@login_required
@can_create(Room)
def new_room(request):
"""Nouvelle chambre """
"""View used to create rooms."""
room = EditRoomForm(request.POST or None)
if room.is_valid():
room.save()
@ -737,7 +742,7 @@ def new_room(request):
@login_required
@can_edit(Room)
def edit_room(request, room, **_kwargs):
""" Edition numero et details de la chambre"""
"""View used to edit rooms."""
room = EditRoomForm(request.POST or None, instance=room)
if room.is_valid():
if room.changed_data:
@ -752,7 +757,7 @@ def edit_room(request, room, **_kwargs):
@login_required
@can_delete(Room)
def del_room(request, room, **_kwargs):
""" Suppression d'un chambre"""
"""View used to delete rooms."""
if request.method == "POST":
try:
room.delete()
@ -777,7 +782,7 @@ def del_room(request, room, **_kwargs):
@login_required
@can_create(ModelSwitch)
def new_model_switch(request):
"""Nouveau modèle de switch"""
"""View used to create switch models."""
model_switch = EditModelSwitchForm(request.POST or None)
if model_switch.is_valid():
model_switch.save()
@ -793,8 +798,7 @@ def new_model_switch(request):
@login_required
@can_edit(ModelSwitch)
def edit_model_switch(request, model_switch, **_kwargs):
""" Edition d'un modèle de switch"""
"""View used to edit switch models."""
model_switch = EditModelSwitchForm(request.POST or None, instance=model_switch)
if model_switch.is_valid():
if model_switch.changed_data:
@ -811,7 +815,7 @@ def edit_model_switch(request, model_switch, **_kwargs):
@login_required
@can_delete(ModelSwitch)
def del_model_switch(request, model_switch, **_kwargs):
""" Suppression d'un modèle de switch"""
"""View used to delete switch models."""
if request.method == "POST":
try:
model_switch.delete()
@ -838,7 +842,7 @@ def del_model_switch(request, model_switch, **_kwargs):
@login_required
@can_create(SwitchBay)
def new_switch_bay(request):
"""Nouvelle baie de switch"""
"""View used to create switch bays."""
switch_bay = EditSwitchBayForm(request.POST or None)
if switch_bay.is_valid():
switch_bay.save()
@ -854,7 +858,7 @@ def new_switch_bay(request):
@login_required
@can_edit(SwitchBay)
def edit_switch_bay(request, switch_bay, **_kwargs):
""" Edition d'une baie de switch"""
"""View used to edit switch bays."""
switch_bay = EditSwitchBayForm(request.POST or None, instance=switch_bay)
if switch_bay.is_valid():
if switch_bay.changed_data:
@ -871,7 +875,7 @@ def edit_switch_bay(request, switch_bay, **_kwargs):
@login_required
@can_delete(SwitchBay)
def del_switch_bay(request, switch_bay, **_kwargs):
""" Suppression d'une baie de switch"""
"""View used to delete switch bays."""
if request.method == "POST":
try:
switch_bay.delete()
@ -898,8 +902,7 @@ def del_switch_bay(request, switch_bay, **_kwargs):
@login_required
@can_create(Building)
def new_building(request):
"""New Building of a dorm
Nouveau batiment"""
"""View used to create buildings."""
building = EditBuildingForm(request.POST or None)
if building.is_valid():
building.save()
@ -915,8 +918,7 @@ def new_building(request):
@login_required
@can_edit(Building)
def edit_building(request, building, **_kwargs):
"""Edit a building
Edition d'un batiment"""
"""View used to edit buildings."""
building = EditBuildingForm(request.POST or None, instance=building)
if building.is_valid():
if building.changed_data:
@ -931,8 +933,7 @@ def edit_building(request, building, **_kwargs):
@login_required
@can_delete(Building)
def del_building(request, building, **_kwargs):
"""Delete a building
Suppression d'un batiment"""
"""View used to delete buildings."""
if request.method == "POST":
try:
building.delete()
@ -959,8 +960,7 @@ def del_building(request, building, **_kwargs):
@login_required
@can_create(Dormitory)
def new_dormitory(request):
"""A new dormitory
Nouvelle residence"""
"""View used to create dormitories."""
dormitory = EditDormitoryForm(request.POST or None)
if dormitory.is_valid():
dormitory.save()
@ -976,8 +976,7 @@ def new_dormitory(request):
@login_required
@can_edit(Dormitory)
def edit_dormitory(request, dormitory, **_kwargs):
"""Edit a dormitory
Edition d'une residence"""
"""View used to edit dormitories."""
dormitory = EditDormitoryForm(request.POST or None, instance=dormitory)
if dormitory.is_valid():
if dormitory.changed_data:
@ -994,8 +993,7 @@ def edit_dormitory(request, dormitory, **_kwargs):
@login_required
@can_delete(Dormitory)
def del_dormitory(request, dormitory, **_kwargs):
"""Delete a dormitory
Suppression d'une residence"""
"""View used to delete dormitories."""
if request.method == "POST":
try:
dormitory.delete()
@ -1022,7 +1020,7 @@ def del_dormitory(request, dormitory, **_kwargs):
@login_required
@can_create(ConstructorSwitch)
def new_constructor_switch(request):
"""Nouveau constructeur de switch"""
"""View used to create switch constructors."""
constructor_switch = EditConstructorSwitchForm(request.POST or None)
if constructor_switch.is_valid():
constructor_switch.save()
@ -1038,8 +1036,7 @@ def new_constructor_switch(request):
@login_required
@can_edit(ConstructorSwitch)
def edit_constructor_switch(request, constructor_switch, **_kwargs):
""" Edition d'un constructeur de switch"""
"""View used to edit switch constructors."""
constructor_switch = EditConstructorSwitchForm(
request.POST or None, instance=constructor_switch
)
@ -1058,7 +1055,7 @@ def edit_constructor_switch(request, constructor_switch, **_kwargs):
@login_required
@can_delete(ConstructorSwitch)
def del_constructor_switch(request, constructor_switch, **_kwargs):
""" Suppression d'un constructeur de switch"""
"""View used to delete switch constructors."""
if request.method == "POST":
try:
constructor_switch.delete()
@ -1085,7 +1082,7 @@ def del_constructor_switch(request, constructor_switch, **_kwargs):
@login_required
@can_create(PortProfile)
def new_port_profile(request):
"""Create a new port profile"""
"""View used to create port profiles."""
port_profile = EditPortProfileForm(request.POST or None)
if port_profile.is_valid():
port_profile.save()
@ -1101,7 +1098,7 @@ def new_port_profile(request):
@login_required
@can_edit(PortProfile)
def edit_port_profile(request, port_profile, **_kwargs):
"""Edit a port profile"""
"""View used to edit port profiles."""
port_profile = EditPortProfileForm(request.POST or None, instance=port_profile)
if port_profile.is_valid():
if port_profile.changed_data:
@ -1118,7 +1115,7 @@ def edit_port_profile(request, port_profile, **_kwargs):
@login_required
@can_delete(PortProfile)
def del_port_profile(request, port_profile, **_kwargs):
"""Delete a port profile"""
"""View used to delete port profiles."""
if request.method == "POST":
try:
port_profile.delete()
@ -1136,7 +1133,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 """
"""View used to create switch modules."""
module = EditModuleForm(request.POST or None)
if module.is_valid():
module.save()
@ -1150,7 +1147,7 @@ def add_module(request):
@login_required
@can_edit(ModuleSwitch)
def edit_module(request, module_instance, **_kwargs):
""" View used to edit a Module object """
"""View used to edit switch modules."""
module = EditModuleForm(request.POST or None, instance=module_instance)
if module.is_valid():
if module.changed_data:
@ -1165,7 +1162,7 @@ def edit_module(request, module_instance, **_kwargs):
@login_required
@can_delete(ModuleSwitch)
def del_module(request, module, **_kwargs):
"""Compleete delete a module"""
"""View used to delete switch modules."""
if request.method == "POST":
try:
module.delete()
@ -1190,7 +1187,7 @@ def del_module(request, module, **_kwargs):
@login_required
@can_create(ModuleOnSwitch)
def add_module_on(request):
"""Add a module to a switch"""
"""View used to add a module to a switch."""
module_switch = EditSwitchModuleForm(request.POST or None)
if module_switch.is_valid():
module_switch.save()
@ -1206,7 +1203,7 @@ def add_module_on(request):
@login_required
@can_edit(ModuleOnSwitch)
def edit_module_on(request, module_instance, **_kwargs):
""" View used to edit a Module object """
"""View used to edit a module on a switch."""
module = EditSwitchModuleForm(request.POST or None, instance=module_instance)
if module.is_valid():
if module.changed_data:
@ -1221,7 +1218,7 @@ def edit_module_on(request, module_instance, **_kwargs):
@login_required
@can_delete(ModuleOnSwitch)
def del_module_on(request, module, **_kwargs):
"""Compleete delete a module"""
"""View used to delete a module on a switch."""
if request.method == "POST":
try:
module.delete()
@ -1244,9 +1241,7 @@ def del_module_on(request, module, **_kwargs):
def make_machine_graph():
"""
Create the graph of switchs, machines and access points.
"""
"""Create the graph of switches, machines and access points."""
dico = {
"subs": [],
"links": [],
@ -1284,7 +1279,7 @@ def make_machine_graph():
"machines": [],
}
)
# Visit all switchs in this building
# Visit all switches in this building
for switch in (
Switch.objects.filter(switchbay__building=building)
.prefetch_related(
@ -1311,7 +1306,7 @@ def make_machine_graph():
"ports": [],
}
)
# visit all ports of this switch and add the switchs linked to it
# visit all ports of this switch and add the switches linked to it
for port in switch.ports.filter(related__isnull=False).select_related(
"related__switch"
):
@ -1365,29 +1360,29 @@ def make_machine_graph():
links, new_detected = recursive_switchs(missing[0], None, [missing[0]])
for link in links:
dico["links"].append(link)
# Update the lists of missings and already detected switchs
# Update the lists of missings and already detected switches
missing = [i for i in missing if i not in new_detected]
detected += new_detected
# If the switch have no ports, don't explore it and hop to the next one
# If the switch has no ports, don't explore it and hop to the next one
else:
del missing[0]
# Switchs that are not connected or not in a building
# Switches that are not connected or not in a building
for switch in Switch.objects.filter(switchbay__isnull=True).exclude(
ports__related__isnull=False
):
dico["alone"].append({"id": switch.id, "name": switch.get_name})
# generate the dot file
# Generate the dot file
dot_data = generate_dot(dico, "topologie/graph_switch.dot")
# Create a temporary file to store the dot data
f = tempfile.NamedTemporaryFile(mode="w+", encoding="utf-8", delete=False)
with f:
f.write(dot_data)
unflatten = Popen( # unflatten the graph to make it look better
unflatten = Popen( # Unflatten the graph to make it look better
["unflatten", "-l", "3", f.name], stdout=PIPE
)
Popen( # pipe the result of the first command into the second
Popen( # Pipe the result of the first command into the second
["dot", "-Tpng", "-o", MEDIA_ROOT + "/images/switchs.png"],
stdin=unflatten.stdout,
stdout=PIPE,
@ -1395,10 +1390,15 @@ def make_machine_graph():
def generate_dot(data, template):
"""create the dot file
:param data: dictionary passed to the template
:param template: path to the dot template
:return: all the lines of the dot file"""
"""Generate a dot file from the data and template given.
Args:
data: dictionary passed to the template.
template: path to the dot template.
Returns:
All the lines of the dot file.
"""
t = loader.get_template(template)
if not isinstance(t, Template) and not (
hasattr(t, "template") and isinstance(t.template, Template)
@ -1415,18 +1415,19 @@ def generate_dot(data, template):
def recursive_switchs(switch_start, switch_before, detected):
"""Visit the switch and travel to the switchs linked to it.
:param switch_start: the switch to begin the visit on
: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
:return: A list of all the links found and a list of
all the switchs visited
"""Visit the switch and travel to the switches linked to it.
Args:
switch_start: the switch to begin the visit on.
switch_before: the switch that you come from. None if switch_start is the first one.
detected: list of all switches already visited. None if switch_start is the first one.
Returns:
A list of all the links found and a list of all the switches visited.
"""
detected.append(switch_start)
links_return = [] # list of dictionaries of the links to be detected
# create links to every switchs below
links_return = [] # List of dictionaries of the links to be detected
# Create links to every switches below
for port in switch_start.ports.filter(related__isnull=False):
# Not the switch that we come from, not the current switch
if (
@ -1440,11 +1441,11 @@ def recursive_switchs(switch_start, switch_before, detected):
}
links_return.append(links) # Add current and below levels links
# go down on every related switchs
# Go down on every related switches
for port in switch_start.ports.filter(related__isnull=False):
# The switch at the end of this link has not been visited
if port.related.switch not in detected:
# explore it and get the results
# Explore it and get the results
links_down, detected = recursive_switchs(
port.related.switch, switch_start, detected
)