Ce serveur Gitlab sera éteint le 30 juin 2020, pensez à migrer vos projets vers les serveurs gitlab-research.centralesupelec.fr et gitlab-student.centralesupelec.fr !

views.py 33 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# 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.
chirac's avatar
chirac committed
22 23
"""
Page des vues de l'application topologie
24

chirac's avatar
chirac committed
25 26 27 28 29 30 31 32 33 34 35
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
"""
36 37
from __future__ import unicode_literals

38
from django.urls import reverse
Dalahro's avatar
Dalahro committed
39 40
from django.shortcuts import render, redirect
from django.contrib import messages
41
from django.contrib.auth.decorators import login_required
Dalahro's avatar
Dalahro committed
42
from django.db import IntegrityError
43
from django.db.models import ProtectedError, Prefetch
44
from django.core.exceptions import ValidationError
45
from django.contrib.staticfiles.storage import staticfiles_storage
Dalahro's avatar
Dalahro committed
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
from users.views import form
from re2o.utils import re2o_paginator, SortTable
from re2o.acl import (
    can_create,
    can_edit,
    can_delete,
    can_view,
    can_view_all,
)
from machines.forms import (
    DomainForm,
    EditInterfaceForm,
    AddInterfaceForm
)
from machines.views import generate_ipv4_mbf_param
from machines.models import Interface
from preferences.models import AssoOption, GeneralOption

from .models import (
66 67 68 69 70
    Switch,
    Port,
    Room,
    Stack,
    ModelSwitch,
71
    ConstructorSwitch,
72 73 74
    AccessPoint,
    SwitchBay,
    Building
75
)
76 77 78 79
from .forms import (
    EditPortForm,
    NewSwitchForm,
    EditSwitchForm,
80 81 82
    AddPortForm,
    EditRoomForm,
    StackForm,
83
    EditModelSwitchForm,
84
    EditConstructorSwitchForm,
85
    CreatePortsForm,
86
    AddAccessPointForm,
87 88 89
    EditAccessPointForm,
    EditSwitchBayForm,
    EditBuildingForm
90
)
91

92 93
from subprocess import Popen,PIPE

chirac's avatar
chirac committed
94

chirac's avatar
chirac committed
95
@login_required
96
@can_view_all(Switch)
Dalahro's avatar
Dalahro committed
97
def index(request):
98
    """ Vue d'affichage de tous les swicthes"""
99 100 101 102 103 104 105 106
    switch_list = (Switch.objects
                   .prefetch_related(Prefetch(
                       'interface_set',
                       queryset=(Interface.objects
                                 .select_related('ipv4__ip_type__extension')
                                 .select_related('domain__extension'))
                   ))
                   .select_related('stack'))
107 108 109 110 111 112
    switch_list = SortTable.sort(
        switch_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX
    )
113
    pagination_number = GeneralOption.get_cached_value('pagination_number')
114
    switch_list = re2o_paginator(request, switch_list, pagination_number)
115 116 117 118 119
    return render(
        request,
        'topologie/index.html',
        {'switch_list': switch_list}
    )
chirac's avatar
chirac committed
120

Dalahro's avatar
Dalahro committed
121

chirac's avatar
chirac committed
122
@login_required
123 124
@can_view_all(Port)
@can_view(Switch)
125
def index_port(request, switch, switchid):
126
    """ Affichage de l'ensemble des ports reliés à un switch particulier"""
127 128 129 130 131 132 133 134 135 136 137 138
    port_list = (Port.objects
                 .filter(switch=switch)
                 .select_related('room')
                 .select_related('machine_interface__domain__extension')
                 .select_related('machine_interface__machine__user')
                 .select_related('related__switch')
                 .prefetch_related(Prefetch(
                     'related__switch__interface_set',
                     queryset=(Interface.objects
                               .select_related('domain__extension'))
                 ))
                 .select_related('switch'))
139 140 141 142 143 144
    port_list = SortTable.sort(
        port_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_PORT
    )
145 146 147 148 149 150 151 152 153
    return render(
        request,
        'topologie/index_p.html',
        {
            'port_list': port_list,
            'id_switch': switchid,
            'nom_switch': switch
        }
    )
chirac's avatar
chirac committed
154

Dalahro's avatar
Dalahro committed
155

chirac's avatar
chirac committed
156
@login_required
157
@can_view_all(Room)
chirac's avatar
chirac committed
158
def index_room(request):
159
    """ Affichage de l'ensemble des chambres"""
160
    room_list = Room.objects
161 162 163 164 165 166
    room_list = SortTable.sort(
        room_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_ROOM
    )
167
    pagination_number = GeneralOption.get_cached_value('pagination_number')
168
    room_list = re2o_paginator(request, room_list, pagination_number)
169 170 171 172 173
    return render(
        request,
        'topologie/index_room.html',
        {'room_list': room_list}
    )
chirac's avatar
chirac committed
174

chirac's avatar
chirac committed
175

176
@login_required
177 178
@can_view_all(AccessPoint)
def index_ap(request):
179
    """ Affichage de l'ensemble des bornes"""
180 181 182 183 184 185 186
    ap_list = (AccessPoint.objects
               .prefetch_related(Prefetch(
                   'interface_set',
                   queryset=(Interface.objects
                             .select_related('ipv4__ip_type__extension')
                             .select_related('domain__extension'))
               )))
187 188
    ap_list = SortTable.sort(
        ap_list,
189 190 191 192 193
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_BORNE
    )
    pagination_number = GeneralOption.get_cached_value('pagination_number')
194
    ap_list = re2o_paginator(request, ap_list, pagination_number)
195 196 197 198 199
    return render(
        request,
        'topologie/index_ap.html',
        {'ap_list': ap_list}
    )
200 201


202
@login_required
203
@can_view_all(Stack)
204 205
@can_view_all(Building)
@can_view_all(SwitchBay)
206
def index_physical_grouping(request):
chirac's avatar
chirac committed
207
    """Affichage de la liste des stacks (affiche l'ensemble des switches)"""
208 209 210 211
    stack_list = (Stack.objects
                  .prefetch_related(
                      'switch_set__interface_set__domain__extension'
                  ))
212 213
    building_list = Building.objects.all()
    switch_bay_list = SwitchBay.objects.select_related('building')
214 215 216 217 218 219
    stack_list = SortTable.sort(
        stack_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_STACK
    )
220 221 222 223 224 225 226 227 228 229 230 231
    building_list = SortTable.sort(
        building_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_BUILDING
    )
    switch_bay_list = SortTable.sort(
        switch_bay_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_SWITCH_BAY
    )
232 233 234 235 236 237 238 239 240
    return render(
        request,
        'topologie/index_physical_grouping.html',
        {
            'stack_list': stack_list,
            'switch_bay_list': switch_bay_list,
            'building_list': building_list,
        }
    )
241 242


243
@login_required
244 245
@can_view_all(ModelSwitch)
@can_view_all(ConstructorSwitch)
246 247
def index_model_switch(request):
    """ Affichage de l'ensemble des modèles de switches"""
248
    model_switch_list = ModelSwitch.objects.select_related('constructor')
249 250 251 252 253 254 255 256 257 258 259 260 261
    constructor_switch_list = ConstructorSwitch.objects
    model_switch_list = SortTable.sort(
        model_switch_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_MODEL_SWITCH
    )
    constructor_switch_list = SortTable.sort(
        constructor_switch_list,
        request.GET.get('col'),
        request.GET.get('order'),
        SortTable.TOPOLOGIE_INDEX_CONSTRUCTOR_SWITCH
    )
262 263 264 265 266 267 268 269
    return render(
        request,
        'topologie/index_model_switch.html',
        {
            'model_switch_list': model_switch_list,
            'constructor_switch_list': constructor_switch_list,
        }
    )
270 271


chirac's avatar
chirac committed
272
@login_required
273
@can_create(Port)
274
def new_port(request, switchid):
275
    """ Nouveau port"""
Dalahro's avatar
Dalahro committed
276
    try:
277
        switch = Switch.objects.get(pk=switchid)
Dalahro's avatar
Dalahro committed
278 279
    except Switch.DoesNotExist:
        messages.error(request, u"Switch inexistant")
280
        return redirect(reverse('topologie:index'))
Dalahro's avatar
Dalahro committed
281 282 283 284 285
    port = AddPortForm(request.POST or None)
    if port.is_valid():
        port = port.save(commit=False)
        port.switch = switch
        try:
286
            port.save()
Dalahro's avatar
Dalahro committed
287 288
            messages.success(request, "Port ajouté")
        except IntegrityError:
chirac's avatar
chirac committed
289
            messages.error(request, "Ce port existe déjà")
290
        return redirect(reverse(
291
            'topologie:index-port',
292 293 294 295 296 297
            kwargs={'switchid': switchid}
        ))
    return form(
        {'id_switch': switchid, 'topoform': port, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request)
chirac's avatar
chirac committed
298

Dalahro's avatar
Dalahro committed
299

chirac's avatar
chirac committed
300
@login_required
301
@can_edit(Port)
302
def edit_port(request, port_object, **_kwargs):
chirac's avatar
chirac committed
303 304
    """ Edition d'un port. Permet de changer le switch parent et
    l'affectation du port"""
305

306
    port = EditPortForm(request.POST or None, instance=port_object)
Dalahro's avatar
Dalahro committed
307
    if port.is_valid():
308 309 310
        if port.changed_data:
            port.save()
            messages.success(request, "Le port a bien été modifié")
311 312
        return redirect(reverse(
            'topologie:index-port',
313
            kwargs={'switchid': str(port_object.switch.id)}
314 315 316 317 318 319 320 321 322 323
        ))
    return form(
        {
            'id_switch': str(port_object.switch.id),
            'topoform': port,
            'action_name': 'Editer'
        },
        'topologie/topo.html',
        request
    )
chirac's avatar
chirac committed
324

chirac's avatar
chirac committed
325

326
@login_required
327
@can_delete(Port)
328
def del_port(request, port, **_kwargs):
329
    """ Supprime le port"""
Gabriel Detraz's avatar
Gabriel Detraz committed
330 331
    if request.method == "POST":
        try:
332 333
            port.delete()
            messages.success(request, "Le port a été détruit")
Gabriel Detraz's avatar
Gabriel Detraz committed
334
        except ProtectedError:
335 336 337 338 339
            messages.error(
                request,
                ("Le port %s est affecté à un autre objet, impossible "
                 "de le supprimer" % port)
            )
340 341
        return redirect(reverse(
            'topologie:index-port',
342 343
            kwargs={'switchid': str(port.switch.id)}
        ))
chirac's avatar
chirac committed
344 345
    return form({'objet': port}, 'topologie/delete.html', request)

Gabriel Detraz's avatar
Gabriel Detraz committed
346 347

@login_required
348
@can_create(Stack)
349
def new_stack(request):
350
    """Ajoute un nouveau stack : stackid_min, max, et nombre de switches"""
351
    stack = StackForm(request.POST or None)
chirac's avatar
chirac committed
352
    if stack.is_valid():
353
        stack.save()
chirac's avatar
chirac committed
354
        messages.success(request, "Stack crée")
Gabriel Detraz's avatar
Gabriel Detraz committed
355
        return redirect(reverse('topologie:index-physical-grouping'))
356 357 358 359 360
    return form(
        {'topoform': stack, 'action_name': 'Créer'},
        'topologie/topo.html',
        request
    )
361 362 363


@login_required
364
@can_edit(Stack)
365
def edit_stack(request, stack, **_kwargs):
chirac's avatar
chirac committed
366
    """Edition d'un stack (nombre de switches, nom...)"""
367 368
    stack = StackForm(request.POST or None, instance=stack)
    if stack.is_valid():
369 370
        if stack.changed_data:
            stack.save()
Gabriel Detraz's avatar
Gabriel Detraz committed
371
        return redirect(reverse('topologie:index-physical-grouping'))
372 373 374 375 376
    return form(
        {'topoform': stack, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
chirac's avatar
chirac committed
377

378

379
@login_required
380
@can_delete(Stack)
381
def del_stack(request, stack, **_kwargs):
chirac's avatar
chirac committed
382
    """Supprime un stack"""
383 384
    if request.method == "POST":
        try:
385 386
            stack.delete()
            messages.success(request, "La stack a eté détruite")
387
        except ProtectedError:
388 389 390 391 392
            messages.error(
                request,
                ("La stack %s est affectée à un autre objet, impossible "
                 "de la supprimer" % stack)
            )
393
        return redirect(reverse('topologie:index-physical-grouping'))
chirac's avatar
chirac committed
394 395
    return form({'objet': stack}, 'topologie/delete.html', request)

396

397
@login_required
398
@can_edit(Stack)
399
def edit_switchs_stack(request, stack, **_kwargs):
chirac's avatar
chirac committed
400
    """Permet d'éditer la liste des switches dans une stack et l'ajouter"""
401

402 403 404 405 406 407 408 409
    if request.method == "POST":
        pass
    else:
        context = {'stack': stack}
        context['switchs_stack'] = stack.switchs_set.all()
        context['switchs_autres'] = Switch.object.filter(stack=None)


chirac's avatar
chirac committed
410
@login_required
411
@can_create(Switch)
Dalahro's avatar
Dalahro committed
412
def new_switch(request):
chirac's avatar
chirac committed
413 414 415
    """ 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"""
416
    switch = NewSwitchForm(
417 418 419
        request.POST or None,
        user=request.user
    )
420
    interface = AddInterfaceForm(
chirac's avatar
chirac committed
421
        request.POST or None,
422
        user=request.user
423
    )
424
    domain = DomainForm(
chirac's avatar
chirac committed
425 426
        request.POST or None,
        )
427
    if switch.is_valid() and interface.is_valid():
428
        user = AssoOption.get_cached_value('utilisateur_asso')
429
        if not user:
430 431 432 433 434
            messages.error(
                request,
                ("L'user association n'existe pas encore, veuillez le "
                 "créer ou le linker dans preferences")
            )
435
            return redirect(reverse('topologie:index'))
436 437 438 439
        new_switch_obj = switch.save(commit=False)
        new_switch_obj.user = user
        new_interface_obj = interface.save(commit=False)
        domain.instance.interface_parent = new_interface_obj
440
        if domain.is_valid():
441 442 443 444 445 446
            new_domain_obj = domain.save(commit=False)
            new_switch_obj.save()
            new_interface_obj.machine = new_switch_obj
            new_interface_obj.save()
            new_domain_obj.interface_parent = new_interface_obj
            new_domain_obj.save()
447 448
            messages.success(request, "Le switch a été créé")
            return redirect(reverse('topologie:index'))
449
    i_mbf_param = generate_ipv4_mbf_param(interface, False)
450 451 452 453 454 455 456 457 458 459 460
    return form(
        {
            'topoform': interface,
            'machineform': switch,
            'domainform': domain,
            'i_mbf_param': i_mbf_param,
            'device': 'switch',
        },
        'topologie/topo_more.html',
        request
    )
chirac's avatar
chirac committed
461

Dalahro's avatar
Dalahro committed
462

463
@login_required
464
@can_create(Port)
465
def create_ports(request, switchid):
466 467
    """ Création d'une liste de ports pour un switch."""
    try:
468
        switch = Switch.objects.get(pk=switchid)
469 470
    except Switch.DoesNotExist:
        messages.error(request, u"Switch inexistant")
471
        return redirect(reverse('topologie:index'))
472

473
    s_begin = s_end = 0
474 475
    nb_ports = switch.ports.count()
    if nb_ports > 0:
Levy--Falk Hugo's avatar
Levy--Falk Hugo committed
476 477 478
        ports = switch.ports.order_by('port').values('port')
        s_begin = ports.first().get('port')
        s_end = ports.last().get('port')
479

480 481
    port_form = CreatePortsForm(
        request.POST or None,
482
        initial={'begin': s_begin, 'end': s_end}
483
    )
484

485 486 487
    if port_form.is_valid():
        begin = port_form.cleaned_data['begin']
        end = port_form.cleaned_data['end']
488 489 490 491 492
        try:
            switch.create_ports(begin, end)
            messages.success(request, "Ports créés.")
        except ValidationError as e:
            messages.error(request, ''.join(e))
493 494
        return redirect(reverse(
            'topologie:index-port',
495
            kwargs={'switchid': switchid}
496
            ))
497 498 499 500 501
    return form(
        {'id_switch': switchid, 'topoform': port_form},
        'topologie/switch.html',
        request
    )
502

Dalahro's avatar
Dalahro committed
503

chirac's avatar
chirac committed
504
@login_required
505
@can_edit(Switch)
506
def edit_switch(request, switch, switchid):
chirac's avatar
chirac committed
507 508
    """ Edition d'un switch. Permet de chambre nombre de ports,
    place dans le stack, interface et machine associée"""
509

510
    switch_form = EditSwitchForm(
chirac's avatar
chirac committed
511
        request.POST or None,
512
        instance=switch,
513
        user=request.user
chirac's avatar
chirac committed
514
        )
515
    interface_form = EditInterfaceForm(
chirac's avatar
chirac committed
516
        request.POST or None,
517
        instance=switch.interface_set.first(),
518
        user=request.user
chirac's avatar
chirac committed
519
        )
520
    domain_form = DomainForm(
chirac's avatar
chirac committed
521
        request.POST or None,
522
        instance=switch.interface_set.first().domain
chirac's avatar
chirac committed
523
        )
524
    if switch_form.is_valid() and interface_form.is_valid():
525 526 527
        new_switch_obj = switch_form.save(commit=False)
        new_interface_obj = interface_form.save(commit=False)
        new_domain_obj = domain_form.save(commit=False)
528
        if switch_form.changed_data:
529
            new_switch_obj.save()
530
        if interface_form.changed_data:
531
            new_interface_obj.save()
532
        if domain_form.changed_data:
533
            new_domain_obj.save()
534
        messages.success(request, "Le switch a bien été modifié")
Levy--Falk Hugo's avatar
Levy--Falk Hugo committed
535
        return redirect(reverse('topologie:index'))
536 537 538 539 540 541 542 543 544 545 546 547 548
    i_mbf_param = generate_ipv4_mbf_param(interface_form, False)
    return form(
        {
            'id_switch': switchid,
            'topoform': interface_form,
            'machineform': switch_form,
            'domainform': domain_form,
            'i_mbf_param': i_mbf_param,
            'device': 'switch',
        },
        'topologie/topo_more.html',
        request
    )
chirac's avatar
chirac committed
549

chirac's avatar
chirac committed
550

551
@login_required
552 553 554
@can_create(AccessPoint)
def new_ap(request):
    """ Creation d'une ap. Cree en meme temps l'interface et la machine
555 556
    associée. Vue complexe. Appelle successivement les 3 models forms
    adaptés : machine, interface, domain et switch"""
557
    ap = AddAccessPointForm(
558 559 560
        request.POST or None,
        user=request.user
    )
561
    interface = AddInterfaceForm(
562 563 564 565 566 567
        request.POST or None,
        user=request.user
    )
    domain = DomainForm(
        request.POST or None,
        )
568
    if ap.is_valid() and interface.is_valid():
569 570
        user = AssoOption.get_cached_value('utilisateur_asso')
        if not user:
571 572 573 574 575
            messages.error(
                request,
                ("L'user association n'existe pas encore, veuillez le "
                 "créer ou le linker dans preferences")
            )
576
            return redirect(reverse('topologie:index'))
577 578 579 580
        new_ap_obj = ap.save(commit=False)
        new_ap_obj.user = user
        new_interface_obj = interface.save(commit=False)
        domain.instance.interface_parent = new_interface_obj
581
        if domain.is_valid():
582 583 584 585 586 587
            new_domain_obj = domain.save(commit=False)
            new_ap_obj.save()
            new_interface_obj.machine = new_ap_obj
            new_interface_obj.save()
            new_domain_obj.interface_parent = new_interface_obj
            new_domain_obj.save()
588
            messages.success(request, "La borne a été créé")
589
            return redirect(reverse('topologie:index-ap'))
590
    i_mbf_param = generate_ipv4_mbf_param(interface, False)
591 592 593 594 595 596 597 598 599 600 601
    return form(
        {
            'topoform': interface,
            'machineform': ap,
            'domainform': domain,
            'i_mbf_param': i_mbf_param,
            'device': 'wifi ap',
        },
        'topologie/topo_more.html',
        request
    )
602 603 604


@login_required
605
@can_edit(AccessPoint)
606
def edit_ap(request, ap, **_kwargs):
607 608
    """ Edition d'un switch. Permet de chambre nombre de ports,
    place dans le stack, interface et machine associée"""
609
    interface_form = EditInterfaceForm(
610 611
        request.POST or None,
        user=request.user,
612
        instance=ap.interface_set.first()
613
    )
614
    ap_form = EditAccessPointForm(
615 616
        request.POST or None,
        user=request.user,
617
        instance=ap
618 619 620
    )
    domain_form = DomainForm(
        request.POST or None,
621
        instance=ap.interface_set.first().domain
622
        )
623
    if ap_form.is_valid() and interface_form.is_valid():
624 625
        user = AssoOption.get_cached_value('utilisateur_asso')
        if not user:
626 627 628 629 630
            messages.error(
                request,
                ("L'user association n'existe pas encore, veuillez le "
                 "créer ou le linker dans preferences")
            )
631
            return redirect(reverse('topologie:index-ap'))
632 633 634
        new_ap_obj = ap_form.save(commit=False)
        new_interface_obj = interface_form.save(commit=False)
        new_domain_obj = domain_form.save(commit=False)
635
        if ap_form.changed_data:
636
            new_ap_obj.save()
637
        if interface_form.changed_data:
638
            new_interface_obj.save()
639
        if domain_form.changed_data:
640
            new_domain_obj.save()
641
        messages.success(request, "La borne a été modifiée")
642
        return redirect(reverse('topologie:index-ap'))
643 644 645 646 647 648 649 650 651 652 653 654 655
    i_mbf_param = generate_ipv4_mbf_param(interface_form, False)
    return form(
        {
            'topoform': interface_form,
            'machineform': ap_form,
            'domainform': domain_form,
            'i_mbf_param': i_mbf_param,
            'device': 'wifi ap',
        },
        'topologie/topo_more.html',
        request
    )

656

chirac's avatar
chirac committed
657
@login_required
658
@can_create(Room)
chirac's avatar
chirac committed
659
def new_room(request):
660
    """Nouvelle chambre """
chirac's avatar
chirac committed
661 662
    room = EditRoomForm(request.POST or None)
    if room.is_valid():
663
        room.save()
chirac's avatar
chirac committed
664
        messages.success(request, "La chambre a été créé")
665
        return redirect(reverse('topologie:index-room'))
666 667 668 669 670
    return form(
        {'topoform': room, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
chirac's avatar
chirac committed
671

chirac's avatar
chirac committed
672 673

@login_required
674
@can_edit(Room)
675
def edit_room(request, room, **_kwargs):
676
    """ Edition numero et details de la chambre"""
chirac's avatar
chirac committed
677 678
    room = EditRoomForm(request.POST or None, instance=room)
    if room.is_valid():
679 680 681
        if room.changed_data:
            room.save()
            messages.success(request, "La chambre a bien été modifiée")
682
        return redirect(reverse('topologie:index-room'))
683 684 685 686 687
    return form(
        {'topoform': room, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
chirac's avatar
chirac committed
688

chirac's avatar
chirac committed
689 690

@login_required
691
@can_delete(Room)
692
def del_room(request, room, **_kwargs):
693
    """ Suppression d'un chambre"""
chirac's avatar
chirac committed
694
    if request.method == "POST":
695
        try:
696 697
            room.delete()
            messages.success(request, "La chambre/prise a été détruite")
698
        except ProtectedError:
699 700 701 702 703
            messages.error(
                request,
                ("La chambre %s est affectée à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % room)
            )
704
        return redirect(reverse('topologie:index-room'))
705 706 707 708 709
    return form(
        {'objet': room, 'objet_name': 'Chambre'},
        'topologie/delete.html',
        request
    )
710 711 712


@login_required
713
@can_create(ModelSwitch)
714 715 716 717
def new_model_switch(request):
    """Nouveau modèle de switch"""
    model_switch = EditModelSwitchForm(request.POST or None)
    if model_switch.is_valid():
718
        model_switch.save()
719
        messages.success(request, "Le modèle a été créé")
720
        return redirect(reverse('topologie:index-model-switch'))
721 722 723 724 725
    return form(
        {'topoform': model_switch, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
726 727 728


@login_required
729
@can_edit(ModelSwitch)
730
def edit_model_switch(request, model_switch, **_kwargs):
731
    """ Edition d'un modèle de switch"""
732

733 734 735 736
    model_switch = EditModelSwitchForm(
        request.POST or None,
        instance=model_switch
    )
737
    if model_switch.is_valid():
738 739 740
        if model_switch.changed_data:
            model_switch.save()
            messages.success(request, "Le modèle a bien été modifié")
741
        return redirect(reverse('topologie:index-model-switch'))
742 743 744 745 746
    return form(
        {'topoform': model_switch, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
747 748 749


@login_required
750
@can_delete(ModelSwitch)
751
def del_model_switch(request, model_switch, **_kwargs):
752 753 754
    """ Suppression d'un modèle de switch"""
    if request.method == "POST":
        try:
755 756
            model_switch.delete()
            messages.success(request, "Le modèle a été détruit")
757
        except ProtectedError:
758 759 760 761 762
            messages.error(
                request,
                ("Le modèle %s est affectée à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % model_switch)
            )
763
        return redirect(reverse('topologie:index-model-switch'))
764 765 766 767 768
    return form(
        {'objet': model_switch, 'objet_name': 'Modèle de switch'},
        'topologie/delete.html',
        request
    )
769 770


771 772 773 774 775 776 777 778
@login_required
@can_create(SwitchBay)
def new_switch_bay(request):
    """Nouvelle baie de switch"""
    switch_bay = EditSwitchBayForm(request.POST or None)
    if switch_bay.is_valid():
        switch_bay.save()
        messages.success(request, "La baie a été créé")
779
        return redirect(reverse('topologie:index-physical-grouping'))
780 781 782 783 784
    return form(
        {'topoform': switch_bay, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
785 786 787 788


@login_required
@can_edit(SwitchBay)
789
def edit_switch_bay(request, switch_bay, **_kwargs):
790 791 792 793 794 795
    """ Edition d'une baie de switch"""
    switch_bay = EditSwitchBayForm(request.POST or None, instance=switch_bay)
    if switch_bay.is_valid():
        if switch_bay.changed_data:
            switch_bay.save()
            messages.success(request, "Le switch a bien été modifié")
796
        return redirect(reverse('topologie:index-physical-grouping'))
797 798 799 800 801
    return form(
        {'topoform': switch_bay, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
802 803 804 805


@login_required
@can_delete(SwitchBay)
806
def del_switch_bay(request, switch_bay, **_kwargs):
807 808 809 810 811 812
    """ Suppression d'une baie de switch"""
    if request.method == "POST":
        try:
            switch_bay.delete()
            messages.success(request, "La baie a été détruite")
        except ProtectedError:
813 814 815 816 817
            messages.error(
                request,
                ("La baie %s est affecté à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % switch_bay)
            )
818
        return redirect(reverse('topologie:index-physical-grouping'))
819 820 821 822 823
    return form(
        {'objet': switch_bay, 'objet_name': 'Baie de switch'},
        'topologie/delete.html',
        request
    )
824 825


826 827 828 829 830 831 832 833
@login_required
@can_create(Building)
def new_building(request):
    """Nouveau batiment"""
    building = EditBuildingForm(request.POST or None)
    if building.is_valid():
        building.save()
        messages.success(request, "Le batiment a été créé")
834
        return redirect(reverse('topologie:index-physical-grouping'))
835 836 837 838 839
    return form(
        {'topoform': building, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
840 841 842 843


@login_required
@can_edit(Building)
844
def edit_building(request, building, **_kwargs):
845 846 847 848 849 850
    """ Edition d'un batiment"""
    building = EditBuildingForm(request.POST or None, instance=building)
    if building.is_valid():
        if building.changed_data:
            building.save()
            messages.success(request, "Le batiment a bien été modifié")
851
        return redirect(reverse('topologie:index-physical-grouping'))
852 853 854 855 856
    return form(
        {'topoform': building, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
857 858 859 860


@login_required
@can_delete(Building)
861
def del_building(request, building, **_kwargs):
862 863 864 865 866 867
    """ Suppression d'un batiment"""
    if request.method == "POST":
        try:
            building.delete()
            messages.success(request, "La batiment a été détruit")
        except ProtectedError:
868 869 870 871 872
            messages.error(
                request,
                ("Le batiment %s est affecté à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % building)
            )
873
        return redirect(reverse('topologie:index-physical-grouping'))
874 875 876 877 878
    return form(
        {'objet': building, 'objet_name': 'Bâtiment'},
        'topologie/delete.html',
        request
    )
879 880


881
@login_required
882
@can_create(ConstructorSwitch)
883 884 885 886
def new_constructor_switch(request):
    """Nouveau constructeur de switch"""
    constructor_switch = EditConstructorSwitchForm(request.POST or None)
    if constructor_switch.is_valid():
887
        constructor_switch.save()
888
        messages.success(request, "Le constructeur a été créé")
889
        return redirect(reverse('topologie:index-model-switch'))
890 891 892 893 894
    return form(
        {'topoform': constructor_switch, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
895 896 897


@login_required
898
@can_edit(ConstructorSwitch)
899
def edit_constructor_switch(request, constructor_switch, **_kwargs):
900
    """ Edition d'un constructeur de switch"""
901

902 903 904 905
    constructor_switch = EditConstructorSwitchForm(
        request.POST or None,
        instance=constructor_switch
    )
906
    if constructor_switch.is_valid():
907 908 909
        if constructor_switch.changed_data:
            constructor_switch.save()
            messages.success(request, "Le modèle a bien été modifié")
910
        return redirect(reverse('topologie:index-model-switch'))
911 912 913 914 915
    return form(
        {'topoform': constructor_switch, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
916 917 918


@login_required
919
@can_delete(ConstructorSwitch)
920
def del_constructor_switch(request, constructor_switch, **_kwargs):
921 922 923
    """ Suppression d'un constructeur de switch"""
    if request.method == "POST":
        try:
924 925
            constructor_switch.delete()
            messages.success(request, "Le constructeur a été détruit")
926
        except ProtectedError:
927 928 929 930 931
            messages.error(
                request,
                ("Le constructeur %s est affecté à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % constructor_switch)
            )
932
        return redirect(reverse('topologie:index-model-switch'))
933 934 935 936
    return form({
        'objet': constructor_switch,
        'objet_name': 'Constructeur de switch'
        }, 'topologie/delete.html', request)
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031


def make_machine_graph():
    """
    Crée le fichier dot et l'image du graph des Switchs
    """
    #Syntaxe DOT temporaire, A mettre dans un template:
    lignes=['''digraph Switchs {
node [
fontname=Helvetica
fontsize=8
shape=plaintext]
edge[arrowhead=odot,arrowtail=dot]''']
    node_fixe='''node [label=<
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
<FONT FACE="Helvetica Bold" COLOR="white">
{}
</FONT></TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" >{}</FONT>
</TD>
<TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" >{}</FONT> 
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" >{}</FONT>
</TD>
<TD ALIGN="LEFT">
<FONT>{}</FONT>
</TD></TR>'''
    node_ports='''<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" >{}</FONT>
</TD>
<TD ALIGN="LEFT">
<FONT>{}</FONT>
</TD></TR>'''
    cluster='''subgraph cluster_{} {{
color=blue;
label="Batiment {}";'''
    end_table='''</TABLE>
>] \"{}_{}\" ;'''
    switch_alone='''{} [label=<
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
<FONT FACE="Helvetica Bold" COLOR="white">
{}
</FONT></TD></TR>
</TABLE>
>]'''
    missing=[]
    detected=[]
    for sw in Switch.objects.all():
        if(sw not in detected):
            missing.append(sw)
    for building in Building.objects.all():
        lignes.append(cluster.format(len(lignes),building))
        for switch in Switch.objects.filter(switchbay__building=building):
            lignes.append(node_fixe.format(switch.main_interface().domain.name,"Modèle",switch.model,"Nombre de ports",switch.number))
            for p in switch.ports.all().filter(related__isnull=False):
                lignes.append(node_ports.format(p.port,p.related.switch.main_interface().domain.name))
            lignes.append(end_table.format(building.id,switch.id))
        lignes.append("}")
    while(missing!=[]):
        lignes,new_detected=recursive_switchs(missing[0].ports.all().filter(related=None).first(),None,lignes,[missing[0]])
        missing=[i for i in missing if i not in new_detected]
        detected+=new_detected
    for switch in Switch.objects.all().filter(switchbay__isnull=True).exclude(ports__related__isnull=False):
        lignes.append(switch_alone.format(switch.id,switch.main_interface().domain.name))
    lignes.append("}")
    fichier = open("media/images/switchs.dot","w")
    for ligne in lignes:
        fichier.write(ligne+"\n")
    fichier.close()
    unflatten = Popen(["unflatten","-l", "3", "media/images/switchs.dot"], stdout=PIPE)
    image = Popen(["dot", "-Tpng", "-o", "media/images/switchs.png"], stdin=unflatten.stdout, stdout=PIPE)


def recursive_switchs(port_start, switch_before, lignes,detected):
    """
    Parcour récursivement le switchs auquel appartient port_start pour trouver les ports suivants liés
    """
    l_ports=port_start.switch.ports.filter(related__isnull=False)
    for port in l_ports:
        if port.related.switch!=switch_before and port.related.switch!=port.switch:
            links=[]
            for sw in [switch for switch in [port_start.switch,port.related.switch]]:
                if(sw not in detected):
                    detected.append(sw)
                if(sw.switchbay.building):
                    links.append("\"{}_{}\"".format(sw.switchbay.building.id,sw.id))
                else:
                    links.append("\"{}\"".format(sw.id))
            lignes.append(links[0]+" -> "+links[1])
            lignes, detected = recursive_switchs(port.related, port_start.switch, lignes, detected)
1032
    return (lignes, detected)