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


241
@login_required
242
@can_view_all(ModelSwitch, ConstructorSwitch)
243 244
def index_model_switch(request):
    """ Affichage de l'ensemble des modèles de switches"""
245
    model_switch_list = ModelSwitch.objects.select_related('constructor')
246 247 248 249 250 251 252 253 254 255 256 257 258
    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
    )
259 260 261 262 263 264 265 266
    return render(
        request,
        'topologie/index_model_switch.html',
        {
            'model_switch_list': model_switch_list,
            'constructor_switch_list': constructor_switch_list,
        }
    )
267 268


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

Dalahro's avatar
Dalahro committed
296

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

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

chirac's avatar
chirac committed
322

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

Gabriel Detraz's avatar
Gabriel Detraz committed
343 344

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


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

375

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

393

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

399 400 401 402 403 404 405 406
    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
407
@login_required
408
@can_create(Switch)
Dalahro's avatar
Dalahro committed
409
def new_switch(request):
chirac's avatar
chirac committed
410 411 412
    """ 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"""
413
    switch = NewSwitchForm(
414 415 416
        request.POST or None,
        user=request.user
    )
417
    interface = AddInterfaceForm(
chirac's avatar
chirac committed
418
        request.POST or None,
419
        user=request.user
420
    )
421
    domain = DomainForm(
chirac's avatar
chirac committed
422 423
        request.POST or None,
        )
424
    if switch.is_valid() and interface.is_valid():
425
        user = AssoOption.get_cached_value('utilisateur_asso')
426
        if not user:
427 428 429 430 431
            messages.error(
                request,
                ("L'user association n'existe pas encore, veuillez le "
                 "créer ou le linker dans preferences")
            )
432
            return redirect(reverse('topologie:index'))
433 434 435 436
        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
437
        if domain.is_valid():
438 439 440 441 442 443
            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()
444 445
            messages.success(request, "Le switch a été créé")
            return redirect(reverse('topologie:index'))
446
    i_mbf_param = generate_ipv4_mbf_param(interface, False)
447 448 449 450 451 452 453 454 455 456 457
    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
458

Dalahro's avatar
Dalahro committed
459

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

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

477 478
    port_form = CreatePortsForm(
        request.POST or None,
479
        initial={'begin': s_begin, 'end': s_end}
480
    )
481

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

Dalahro's avatar
Dalahro committed
500

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

507
    switch_form = EditSwitchForm(
chirac's avatar
chirac committed
508
        request.POST or None,
509
        instance=switch,
510
        user=request.user
chirac's avatar
chirac committed
511
        )
512
    interface_form = EditInterfaceForm(
chirac's avatar
chirac committed
513
        request.POST or None,
514
        instance=switch.interface_set.first(),
515
        user=request.user
chirac's avatar
chirac committed
516
        )
517
    domain_form = DomainForm(
chirac's avatar
chirac committed
518
        request.POST or None,
519
        instance=switch.interface_set.first().domain
chirac's avatar
chirac committed
520
        )
521
    if switch_form.is_valid() and interface_form.is_valid():
522 523 524
        new_switch_obj = switch_form.save(commit=False)
        new_interface_obj = interface_form.save(commit=False)
        new_domain_obj = domain_form.save(commit=False)
525
        if switch_form.changed_data:
526
            new_switch_obj.save()
527
        if interface_form.changed_data:
528
            new_interface_obj.save()
529
        if domain_form.changed_data:
530
            new_domain_obj.save()
531
        messages.success(request, "Le switch a bien été modifié")
Levy--Falk Hugo's avatar
Levy--Falk Hugo committed
532
        return redirect(reverse('topologie:index'))
533 534 535 536 537 538 539 540 541 542 543 544 545
    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
546

chirac's avatar
chirac committed
547

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


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

653

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

chirac's avatar
chirac committed
669 670

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

chirac's avatar
chirac committed
686 687

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


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


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

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


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


768 769 770 771 772 773 774 775
@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éé")
776
        return redirect(reverse('topologie:index-physical-grouping'))
777 778 779 780 781
    return form(
        {'topoform': switch_bay, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
782 783 784 785


@login_required
@can_edit(SwitchBay)
786
def edit_switch_bay(request, switch_bay, **_kwargs):
787 788 789 790 791 792
    """ 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é")
793
        return redirect(reverse('topologie:index-physical-grouping'))
794 795 796 797 798
    return form(
        {'topoform': switch_bay, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
799 800 801 802


@login_required
@can_delete(SwitchBay)
803
def del_switch_bay(request, switch_bay, **_kwargs):
804 805 806 807 808 809
    """ 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:
810 811 812 813 814
            messages.error(
                request,
                ("La baie %s est affecté à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % switch_bay)
            )
815
        return redirect(reverse('topologie:index-physical-grouping'))
816 817 818 819 820
    return form(
        {'objet': switch_bay, 'objet_name': 'Baie de switch'},
        'topologie/delete.html',
        request
    )
821 822


823 824 825 826 827 828 829 830
@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éé")
831
        return redirect(reverse('topologie:index-physical-grouping'))
832 833 834 835 836
    return form(
        {'topoform': building, 'action_name': 'Ajouter'},
        'topologie/topo.html',
        request
    )
837 838 839 840


@login_required
@can_edit(Building)
841
def edit_building(request, building, **_kwargs):
842 843 844 845 846 847
    """ 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é")
848
        return redirect(reverse('topologie:index-physical-grouping'))
849 850 851 852 853
    return form(
        {'topoform': building, 'action_name': 'Editer'},
        'topologie/topo.html',
        request
    )
854 855 856 857


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


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


@login_required
895
@can_edit(ConstructorSwitch)
896
def edit_constructor_switch(request, constructor_switch, **_kwargs):
897
    """ Edition d'un constructeur de switch"""
898

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


@login_required
916
@can_delete(ConstructorSwitch)
917
def del_constructor_switch(request, constructor_switch, **_kwargs):
918 919 920
    """ Suppression d'un constructeur de switch"""
    if request.method == "POST":
        try:
921 922
            constructor_switch.delete()
            messages.success(request, "Le constructeur a été détruit")
923
        except ProtectedError:
924 925 926 927 928
            messages.error(
                request,
                ("Le constructeur %s est affecté à un autre objet, impossible "
                 "de la supprimer (switch ou user)" % constructor_switch)
            )
929
        return redirect(reverse('topologie:index-model-switch'))
930 931 932 933
    return form({
        'objet': constructor_switch,
        'objet_name': 'Constructeur de switch'
        }, 'topologie/delete.html', request)
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956


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">
957
<FONT COLOR="#7B7B7B" >{}</FONT>
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
</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)
1029
    return (lignes, detected)