views.py 34.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE 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 3 of the License, or (at your option)
# any later version.
#
# CIRCLE 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 CIRCLE.  If not, see <http://www.gnu.org/licenses/>.

18 19
from collections import OrderedDict

20
from netaddr import IPNetwork
21 22
from django.views.generic import (TemplateView, UpdateView, DeleteView,
                                  CreateView)
23
from django.core.exceptions import ValidationError
24
from django.core.urlresolvers import reverse_lazy
25
from django.shortcuts import render, redirect, get_object_or_404
26
from django.http import HttpResponse, Http404
27
from django.db.models import Q
28 29 30

from django_tables2 import SingleTableView

Kálmán Viktor committed
31 32 33
from firewall.models import (
    Host, Vlan, Domain, Group, Record, BlacklistItem, Rule, VlanGroup,
    SwitchPort, EthernetDevice, Firewall)
34
from vm.models import Interface
Kálmán Viktor committed
35 36 37 38
from .tables import (
    HostTable, VlanTable, SmallHostTable, DomainTable, GroupTable,
    RecordTable, BlacklistItemTable, RuleTable, VlanGroupTable,
    SmallRuleTable, SmallGroupRuleTable, SmallRecordTable, SwitchPortTable,
39
    SmallDhcpTable, FirewallTable, FirewallRuleTable,
Kálmán Viktor committed
40 41 42 43 44
)
from .forms import (
    HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistItemForm,
    RuleForm, VlanGroupForm, SwitchPortForm, FirewallForm
)
45 46

from django.contrib import messages
47
from django.contrib.messages.views import SuccessMessageMixin
48 49
from django.views.generic.edit import FormMixin
from django.utils.translation import ugettext_lazy as _
50
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
51 52
# from django.db.models import Q
from operator import itemgetter
53
from itertools import chain
Kálmán Viktor committed
54
from dashboard.views import AclUpdateView
55
from dashboard.forms import AclUserOrGroupAddForm
56

57 58 59
try:
    from django.http import JsonResponse
except ImportError:
Bach Dániel committed
60
    from django.utils import simplejson
61

62 63 64 65 66 67 68 69 70 71 72 73
    class JsonResponse(HttpResponse):
        """JSON response for Django < 1.7
        https://gist.github.com/philippeowagner/3179eb475fe1795d6515
        """
        def __init__(self, content, mimetype='application/json',
                     status=None, content_type=None):
            super(JsonResponse, self).__init__(
                content=simplejson.dumps(content),
                mimetype=mimetype,
                status=status,
                content_type=content_type)

74

75 76 77 78 79 80 81 82 83 84
class MagicMixin(object):

    def get(self, *args, **kwargs):
        if self.request.is_ajax():
            result = self._get_ajax(*args, **kwargs)
            return JsonResponse({k: unicode(result[k] or "") for k in result})
        else:
            return super(MagicMixin, self).get(*args, **kwargs)


85 86 87 88 89
class InitialOwnerMixin(FormMixin):
    def get_initial(self):
        initial = super(InitialOwnerMixin, self).get_initial()
        initial['owner'] = self.request.user
        return initial
90 91


92
class IndexView(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
93 94 95 96 97 98
    template_name = "network/index.html"

    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)

        size = 13
99 100
        blacklists = BlacklistItem.objects.all().order_by(
            '-modified_at')[:size]
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
        domains = Domain.objects.all().order_by('-modified_at')[:size]
        groups = Group.objects.all().order_by('-modified_at')[:size]
        hosts = Host.objects.all().order_by('-modified_at')[:size]
        records = Record.objects.all().order_by('-modified_at')[:size]
        vlans = Vlan.objects.all().order_by('-modified_at')[:size]
        vlangroups = VlanGroup.objects.all().order_by('-modified_at')[:size]
        rules = Rule.objects.all().order_by('-modified_at')[:size]

        result_list = []
        for i in (sorted(chain(domains, groups, hosts, records, vlans,
                               vlangroups, rules),
                         key=lambda x: x.modified_at, reverse=True)[:size]):
            result_list.append(
                {
                    'class_name': unicode(i.__class__.__name__),
                    'modified_at': i.modified_at,
                    'created_at': i.created_at,
                    'name': unicode(i),
                    'link': i.get_absolute_url()
                })

        context['latest_blacklists'] = blacklists
        context['latest'] = result_list
        return context


127 128
class BlacklistList(LoginRequiredMixin, SuperuserRequiredMixin,
                    SingleTableView):
129 130
    model = BlacklistItem
    table_class = BlacklistItemTable
131 132 133 134
    template_name = "network/blacklist-list.html"
    table_pagination = False


135 136
class BlacklistDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                      SuccessMessageMixin, UpdateView):
137
    model = BlacklistItem
138
    template_name = "network/blacklist-edit.html"
139
    form_class = BlacklistItemForm
140
    success_message = _(u'Successfully modified blacklist item %(ipv4)s.')
141 142 143 144 145 146 147 148 149 150 151

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.blacklist', kwargs=self.kwargs)

    def get_context_data(self, **kwargs):
        context = super(BlacklistDetail, self).get_context_data(**kwargs)
        context['blacklist_pk'] = self.object.pk
        return context


152 153
class BlacklistCreate(LoginRequiredMixin, SuperuserRequiredMixin,
                      SuccessMessageMixin, CreateView):
154
    model = BlacklistItem
155
    template_name = "network/blacklist-create.html"
156
    form_class = BlacklistItemForm
157
    success_message = _(u'Successfully created blacklist item %(ipv4)s')
158 159


160
class BlacklistDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
161
    model = BlacklistItem
162 163 164 165 166 167
    template_name = "network/confirm/base_delete.html"

    def get_context_data(self, **kwargs):
        """ display more information about the object """
        context = super(BlacklistDelete, self).get_context_data(**kwargs)
        if 'pk' in self.kwargs:
168
            to_delete = BlacklistItem.objects.get(pk=self.kwargs['pk'])
169
            context['object'] = "%s - %s" % (to_delete.ipv4, to_delete.reason)
170 171 172 173 174 175 176 177 178 179
            return context

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return self.request.POST['next']
        else:
            return reverse_lazy('network.blacklist_list')


180
class DomainList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
181 182 183 184 185 186
    model = Domain
    table_class = DomainTable
    template_name = "network/domain-list.html"
    table_pagination = False


187 188
class DomainDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                   SuccessMessageMixin, UpdateView):
189 190 191
    model = Domain
    template_name = "network/domain-edit.html"
    form_class = DomainForm
192
    success_message = _(u'Successfully modified domain %(name)s.')
193 194 195 196 197 198 199

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.domain', kwargs=self.kwargs)

    def get_context_data(self, *args, **kwargs):
        context = super(DomainDetail, self).get_context_data(**kwargs)
200 201 202 203 204 205 206
        self.object = self.get_object()
        context['domain_pk'] = self.object.pk

        q = Record.objects.filter(
            domain=self.object,
            host__in=Host.objects.filter(
                interface__in=Interface.objects.filter(
207
                    instance__destroyed_at=None)
208 209
            )
        )
210 211 212 213
        context['record_list'] = SmallRecordTable(q)
        return context


214
class DomainCreate(LoginRequiredMixin, SuperuserRequiredMixin,
215
                   SuccessMessageMixin, InitialOwnerMixin, CreateView):
216 217 218
    model = Domain
    template_name = "network/domain-create.html"
    form_class = DomainForm
219
    success_message = _(u'Successfully created domain %(name)s.')
220 221


222
class DomainDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
223 224 225 226 227 228 229 230 231 232 233 234 235
    model = Domain
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return self.request.POST['next']
        else:
            return reverse_lazy('network.domain_list')

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        if unicode(self.object) != request.POST.get('confirm'):
236
            messages.error(request, _(u"Object name does not match."))
237 238 239
            return self.get(request, *args, **kwargs)

        response = super(DomainDelete, self).delete(request, *args, **kwargs)
240
        messages.success(request, _(u"Domain successfully deleted."))
241 242 243 244 245
        return response

    def get_context_data(self, **kwargs):
        context = super(DomainDelete, self).get_context_data(**kwargs)

246
        records_from_hosts = _(u'Records from hosts')
247 248 249 250 251
        deps = []
        # vlans
        vlans = Vlan.objects.filter(domain=self.object).all()
        if len(vlans) > 0:
            deps.append({
252
                'name': _('Vlans'),
253 254 255 256 257 258 259
                'data': vlans
            })

            # hosts
            hosts = Host.objects.filter(vlan__in=deps[0]['data'])
            if len(hosts) > 0:
                deps.append({
260
                    'name': _('Hosts'),
261 262 263 264 265
                    'data':  hosts
                })

                # records
                records = Record.objects.filter(
266 267
                    host__in=deps[1]['data']
                    # Q(domain=self.object) | (host__in=deps[1]['data'])
268 269 270
                )
                if len(records) > 0:
                    deps.append({
271
                        'name': records_from_hosts,
272 273 274
                        'data': records
                    })

275 276 277 278
        records = Record.objects.filter(domain=self.object)
        if len(records) > 0:
            # to filter out doubles (records from hosts and domains)
            indexes = map(itemgetter('name'), deps)
279
            n = indexes.index(records_from_hosts) if len(indexes) > 0 else 0
280
            deps.append({
281
                'name': u'Records only from the domain',
282 283 284 285
                'data': records.exclude(pk__in=deps[n]['data']) if n > 0
                else records
            })

286 287 288 289 290
        context['deps'] = deps
        context['confirmation'] = True
        return context


Kálmán Viktor committed
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
class FirewallList(LoginRequiredMixin, SuperuserRequiredMixin,
                   SingleTableView):
    model = Firewall
    table_class = FirewallTable
    template_name = "network/firewall-list.html"
    table_pagination = False


class FirewallDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                     SuccessMessageMixin, UpdateView):
    model = Firewall
    template_name = "network/firewall-edit.html"
    form_class = FirewallForm
    success_message = _(u'Succesfully modified firewall.')

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.firewall', kwargs=self.kwargs)

    def get_context_data(self, **kwargs):
        context = super(FirewallDetail, self).get_context_data(**kwargs)
312 313 314
        rules = Rule.objects.filter(firewall=self.object)
        context['rule_table'] = FirewallRuleTable(rules,
                                                  request=self.request)
Kálmán Viktor committed
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
        return context


class FirewallCreate(LoginRequiredMixin, SuperuserRequiredMixin,
                     SuccessMessageMixin, CreateView):
    model = Firewall
    template_name = "network/firewall-create.html"
    form_class = FirewallForm
    success_message = _(u'Successfully created firewall.')


class FirewallDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
    model = Firewall
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return next
        else:
            return reverse_lazy('network.firewall_list')


338
class GroupList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
339 340 341 342 343 344
    model = Group
    table_class = GroupTable
    template_name = "network/group-list.html"
    table_pagination = False


345
class GroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
346
                  SuccessMessageMixin, InitialOwnerMixin, CreateView):
347 348 349
    model = Group
    template_name = "network/group-create.html"
    form_class = GroupForm
350
    success_message = _(u'Successfully created host group %(name)s.')
351 352


353 354
class GroupDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                  SuccessMessageMixin, UpdateView):
355 356 357
    model = Group
    template_name = "network/group-edit.html"
    form_class = GroupForm
358
    success_message = _(u'Successfully modified host group %(name)s.')
359 360 361 362 363

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.group', kwargs=self.kwargs)

364 365 366
    def get_context_data(self, *args, **kwargs):
        context = super(GroupDetail, self).get_context_data(**kwargs)

367 368
        context['group_pk'] = self.object.pk

369 370 371 372 373
        # records
        q = Rule.objects.filter(hostgroup=self.object)
        context['rule_list'] = SmallRuleTable(q)
        return context

374

375
class GroupDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
    model = Group
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return self.request.POST['next']
        else:
            return reverse_lazy('network.group_list')

    def get_context_data(self, *args, **kwargs):
        context = super(GroupDelete, self).get_context_data(**kwargs)
        context['group_pk'] = self.object.pk
        return context


392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
class HostMagicMixin(MagicMixin):
    def _get_ajax(self, *args, **kwargs):
        GET = self.request.GET
        result = {}
        vlan = get_object_or_404(Vlan.objects, pk=GET.get("vlan", ""))
        if "ipv4" in GET:
            try:
                result["ipv6"] = vlan.convert_ipv4_to_ipv6(GET["ipv4"]) or ""
            except:
                result["ipv6"] = ""
        else:
            try:
                result.update(vlan.get_new_address())
            except ValidationError:
                result["ipv4"] = ""
                result["ipv6"] = ""
        return result


411
class HostList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
412 413 414 415 416 417 418 419 420 421 422 423 424 425
    model = Host
    table_class = HostTable
    template_name = "network/host-list.html"
    table_pagination = False

    def get_context_data(self, **kwargs):
        context = super(HostList, self).get_context_data(**kwargs)
        q = Vlan.objects.all().order_by("name")
        context['vlans'] = q
        return context

    def get_table_data(self):
        vlan_id = self.request.GET.get('vlan')
        if vlan_id:
426
            data = Host.objects.filter(vlan=vlan_id).select_related()
427
        else:
428
            data = Host.objects.select_related()
429 430 431 432 433

        search = self.request.GET.get("s")
        if search:
            data = data.filter(Q(hostname__icontains=search) |
                               Q(ipv4=search))  # ipv4 does not work TODO
434 435 436
        return data


437
class HostDetail(HostMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin,
438
                 SuccessMessageMixin, UpdateView):
439 440 441
    model = Host
    template_name = "network/host-edit.html"
    form_class = HostForm
442
    success_message = _(u'Successfully modified host %(hostname)s.')
443

444 445
    def _get_ajax(self, *args, **kwargs):
        if "vlan" not in self.request.GET:
446 447 448
            host = Host.objects.get(pk=kwargs['pk'])
            host = {
                'hostname': host.hostname,
449 450
                'ipv4': str(host.ipv4),
                'ipv6': str(host.ipv6),
451 452
                'fqdn': host.get_fqdn()
            }
453
            return host
454
        else:
455 456 457 458 459
            return super(HostDetail, self)._get_ajax(*args, **kwargs)

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(HostDetail, self).get(request, *args, **kwargs)
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

    def post(self, request, *args, **kwargs):
        pk = self.kwargs.get('pk')
        # this is usually not None (well, with curl and whatnot it can be)
        if pk:
            groups = Host.objects.get(pk=pk).groups.all()
            groups = [i.pk for i in groups]
            # request.POST is immutable
            post_copy = request.POST.copy()
            post_copy.setlist('groups', groups)
            request.POST = post_copy
            return super(HostDetail, self).post(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(HostDetail, self).get_context_data(**kwargs)
        # own rules
        q = Rule.objects.filter(host=self.object).all()
        context['rule_list'] = SmallRuleTable(q)

        # rules from host groups
        group_rule_list = []
        for group in self.object.groups.all():
            q = Rule.objects.filter(hostgroup=group).all()
            group_rule_list.append({
                'table': SmallGroupRuleTable(q),
                'name': unicode(group),
                'pk': group.pk
            })
        context['group_rule_list'] = group_rule_list

        # available groups
        rest = Group.objects.exclude(pk__in=self.object.groups.all()).all()
        context['not_used_groups'] = rest

        # set host pk (we need this for URL-s)
        context['host_pk'] = self.kwargs['pk']

497 498 499
        from network.tables import HostRecordsTable
        context['records_table'] = HostRecordsTable(
            Record.objects.filter(host=self.get_object()),
500
            request=self.request, template="django_tables2/table_no_page.html"
501 502
        )

503 504 505 506 507 508 509
        return context

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.host', kwargs=self.kwargs)


510
class HostCreate(HostMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin,
511
                 SuccessMessageMixin, InitialOwnerMixin, CreateView):
512 513 514
    model = Host
    template_name = "network/host-create.html"
    form_class = HostForm
515
    success_message = _(u'Successfully created host %(hostname)s.')
516

517 518 519 520 521 522 523
    def get_initial(self):
        initial = super(HostCreate, self).get_initial()

        for i in ("vlan", "mac", "hostname"):
            if i in self.request.GET and i not in self.request.POST:
                initial[i] = self.request.GET[i]
        if "vlan" in initial:
524 525
            if not initial['vlan'].isnumeric():
                raise Http404()
526 527 528 529 530 531 532
            vlan = get_object_or_404(Vlan.objects, pk=initial['vlan'])
            try:
                initial.update(vlan.get_new_address())
            except ValidationError as e:
                messages.error(self.request, e.message)
        return initial

533

534
class HostDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
    model = Host
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return self.request.POST['next']
        else:
            return reverse_lazy('network.host_list')

    def get_context_data(self, *args, **kwargs):
        context = super(HostDelete, self).get_context_data(**kwargs)

        deps = []
        records = Record.objects.filter(host=self.object).all()
        if records:
            deps.append({
552
                'name': _('Records'),
553 554 555 556 557 558 559 560 561 562
                'data': records
            })

        context['deps'] = deps
        context['confirmation'] = True
        return context

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        if unicode(self.object) != request.POST.get('confirm'):
563
            messages.error(request, _(u"Object name does not match."))
564 565 566
            return self.get(request, *args, **kwargs)

        response = super(HostDelete, self).delete(request, *args, **kwargs)
567
        messages.success(request, _(u"Host successfully deleted."))
568 569 570
        return response


571
class RecordList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
572 573 574 575 576
    model = Record
    table_class = RecordTable
    template_name = "network/record-list.html"
    table_pagination = False

577 578 579 580 581 582 583 584 585 586 587 588 589
    def get_context_data(self, **kwargs):
        context = super(RecordList, self).get_context_data(**kwargs)
        context['types'] = Record.CHOICES_type
        return context

    def get_table_data(self):
        type_id = self.request.GET.get('type')
        if type_id:
            data = Record.objects.filter(type=type_id).select_related()
        else:
            data = Record.objects.select_related()
        return data

590

591 592
class RecordDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                   SuccessMessageMixin, UpdateView):
593 594 595 596
    model = Record
    template_name = "network/record-edit.html"
    form_class = RecordForm
    # TODO fqdn
597
    success_message = _(u'Successfully modified record.')
598 599 600 601 602 603 604 605 606 607 608 609

    def get_context_data(self, **kwargs):
        context = super(RecordDetail, self).get_context_data(**kwargs)
        context['fqdn'] = self.object.fqdn
        context['record_pk'] = self.object.pk
        return context

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.record', kwargs=self.kwargs)


610
class RecordCreate(LoginRequiredMixin, SuperuserRequiredMixin,
611
                   SuccessMessageMixin, InitialOwnerMixin, CreateView):
612 613 614 615
    model = Record
    template_name = "network/record-create.html"
    form_class = RecordForm
    # TODO fqdn
616
    success_message = _(u'Successfully created record.')
617

618
    def get_initial(self):
619 620 621
        initial = super(RecordCreate, self).get_initial()
        initial['domain'] = self.request.GET.get('domain')

622 623 624 625 626 627 628 629 630 631 632 633 634
        host_pk = self.request.GET.get("host")
        try:
            host = Host.objects.get(pk=host_pk)
        except (Host.DoesNotExist, ValueError):
            host = None

        if host:
            initial.update({
                'type': "CNAME",
                'host': host,
                'address': host.get_fqdn(),
            })

635
        return initial
636

637

638
class RecordDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
639 640 641 642 643 644 645 646 647 648 649
    model = Record
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return self.request.POST['next']
        else:
            return reverse_lazy('network.record_list')


650
class RuleList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
651 652 653 654 655
    model = Rule
    table_class = RuleTable
    template_name = "network/rule-list.html"
    table_pagination = False

656 657 658 659 660 661 662 663 664 665
    def get_context_data(self, **kwargs):
        self.types = OrderedDict([
            ('vlan', _("Vlan")), ('vlangroup', _("Vlan group")),
            ('host', _("Host")), ('hostgroup', _("Host group")),
            ('firewall', _("Firewall"))
        ])
        context = super(RuleList, self).get_context_data(**kwargs)
        context['types'] = self.types
        return context

666
    def get_table_data(self):
667 668 669 670 671 672 673 674
        rules = Rule.objects.select_related('host', 'hostgroup', 'vlan',
                                            'vlangroup', 'firewall',
                                            'foreign_network', 'owner')

        rule_type = self.request.GET.get("type")
        if rule_type and rule_type in self.types.keys():
            rules = rules.filter(**{'%s__isnull' % rule_type: False})
        return rules
675

676

677 678
class RuleDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                 SuccessMessageMixin, UpdateView):
679 680 681
    model = Rule
    template_name = "network/rule-edit.html"
    form_class = RuleForm
682
    success_message = _(u'Successfully modified rule.')
683 684 685 686 687 688 689 690 691 692 693 694 695 696

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.rule', kwargs=self.kwargs)

    def get_context_data(self, **kwargs):
        context = super(RuleDetail, self).get_context_data(**kwargs)

        rule = self.get_object()

        context['rule'] = rule
        return context


697
class RuleCreate(LoginRequiredMixin, SuperuserRequiredMixin,
698
                 SuccessMessageMixin, InitialOwnerMixin, CreateView):
699 700 701
    model = Rule
    template_name = "network/rule-create.html"
    form_class = RuleForm
702
    success_message = _(u'Successfully created rule.')
703

704
    def get_initial(self):
705 706
        initial = super(RuleCreate, self).get_initial()
        initial.update({
707 708
            'host': self.request.GET.get('host'),
            'hostgroup': self.request.GET.get('hostgroup')
709 710
        })
        return initial
711

712

713
class RuleDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
714 715 716 717 718 719 720 721 722 723 724
    model = Rule
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return next
        else:
            return reverse_lazy('network.rule_list')


725 726
class SwitchPortList(LoginRequiredMixin, SuperuserRequiredMixin,
                     SingleTableView):
727 728 729 730 731 732
    model = SwitchPort
    table_class = SwitchPortTable
    template_name = "network/switch-port-list.html"
    table_pagination = False


733 734
class SwitchPortDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                       SuccessMessageMixin, UpdateView):
735 736 737
    model = SwitchPort
    template_name = "network/switch-port-edit.html"
    form_class = SwitchPortForm
738
    success_message = _(u'Succesfully modified switch port.')
739 740 741 742 743 744 745 746 747 748 749 750 751

    def get_success_url(self):
        if 'pk' in self.kwargs:
            return reverse_lazy('network.switch_port', kwargs=self.kwargs)

    def get_context_data(self, **kwargs):
        context = super(SwitchPortDetail, self).get_context_data(**kwargs)
        context['switch_port_pk'] = self.object.pk
        context['devices'] = EthernetDevice.objects.filter(
            switch_port=self.object.pk)
        return context


752 753
class SwitchPortCreate(LoginRequiredMixin, SuperuserRequiredMixin,
                       SuccessMessageMixin, CreateView):
754 755 756
    model = SwitchPort
    template_name = "network/switch-port-create.html"
    form_class = SwitchPortForm
757
    success_message = _(u'Successfully created switch port.')
758 759


760
class SwitchPortDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
761 762 763 764 765 766 767 768 769 770 771
    model = SwitchPort
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return next
        else:
            return reverse_lazy('network.switch_port_list')


772
class VlanList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
773 774 775 776 777 778
    model = Vlan
    table_class = VlanTable
    template_name = "network/vlan-list.html"
    table_pagination = False


Kálmán Viktor committed
779 780 781 782
class VlanAclUpdateView(AclUpdateView):
    model = Vlan


783
class VlanMagicMixin(MagicMixin):
784 785 786 787 788
    def _get_ajax(self, *args, **kwargs):
        GET = self.request.GET
        result = {}
        if "network4" in GET and "network6" in GET:
            try:
789 790 791
                result["ipv6_template"], result["host_ipv6_prefixlen"] = (
                    Vlan._magic_ipv6_template(IPNetwork(GET['network4']),
                                              IPNetwork(GET['network6'])))
792
            except:
793
                result["ipv6_template"] = result["host_ipv6_prefixlen"] = ""
794
        return result
795 796 797


class VlanDetail(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin,
798
                 SuccessMessageMixin, UpdateView):
799 800 801 802 803
    model = Vlan
    template_name = "network/vlan-edit.html"
    form_class = VlanForm
    slug_field = 'vid'
    slug_url_kwarg = 'vid'
804
    success_message = _(u'Succesfully modified vlan %(name)s.')
805 806 807

    def get_context_data(self, **kwargs):
        context = super(VlanDetail, self).get_context_data(**kwargs)
808
        context['host_list'] = SmallHostTable(self.object.host_set.all())
809
        context['dhcp_list'] = SmallDhcpTable(self.object.get_dhcp_clients())
810
        context['vlan_vid'] = self.kwargs.get('vid')
811 812
        context['acl'] = AclUpdateView.get_acl_data(
            self.object, self.request.user, 'network.vlan-acl')
813
        context['aclform'] = AclUserOrGroupAddForm()
814 815 816 817 818
        return context

    success_url = reverse_lazy('network.vlan_list')


819
class VlanCreate(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin,
820
                 SuccessMessageMixin, InitialOwnerMixin, CreateView):
821 822 823
    model = Vlan
    template_name = "network/vlan-create.html"
    form_class = VlanForm
824
    success_message = _(u'Successfully created vlan %(name)s.')
825 826


827
class VlanDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
    model = Vlan
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return next
        else:
            return reverse_lazy('network.vlan_list')

    def get_object(self, queryset=None):
        """ we identify vlans by vid and not pk """
        return Vlan.objects.get(vid=self.kwargs['vid'])

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        if unicode(self.object) != request.POST.get('confirm'):
845
            messages.error(request, _(u"Object name does not match."))
846 847 848
            return self.get(request, *args, **kwargs)

        response = super(VlanDelete, self).delete(request, *args, **kwargs)
849
        messages.success(request, _(u"Vlan successfully deleted."))
850 851 852 853 854 855 856 857 858 859
        return response

    def get_context_data(self, **kwargs):
        context = super(VlanDelete, self).get_context_data(**kwargs)

        deps = []
        # hosts
        hosts = Host.objects.filter(vlan=self.object).all()
        if len(hosts) > 0:
            deps.append({
860
                'name': _('Hosts'),
861 862 863 864 865 866 867
                'data': hosts
            })

            # records
            records = Record.objects.filter(host__in=deps[0]['data'])
            if len(records) > 0:
                deps.append({
868
                    'name': _('Records'),
869 870 871 872 873 874 875 876
                    'data':  records
                })

        context['deps'] = deps
        context['confirmation'] = True
        return context


877 878
class VlanGroupList(LoginRequiredMixin, SuperuserRequiredMixin,
                    SingleTableView):
879 880 881 882 883 884
    model = VlanGroup
    table_class = VlanGroupTable
    template_name = "network/vlan-group-list.html"
    table_pagination = False


885 886
class VlanGroupDetail(LoginRequiredMixin, SuperuserRequiredMixin,
                      SuccessMessageMixin, UpdateView):
887 888 889 890
    model = VlanGroup
    template_name = "network/vlan-group-edit.html"
    form_class = VlanGroupForm
    success_url = reverse_lazy('network.vlan_group_list')
891
    success_message = _(u'Successfully modified vlan group %(name)s.')
892 893 894 895 896 897 898

    def get_context_data(self, *args, **kwargs):
        context = super(VlanGroupDetail, self).get_context_data(**kwargs)
        context['vlangroup_pk'] = self.object.pk
        return context


899
class VlanGroupCreate(LoginRequiredMixin, SuperuserRequiredMixin,
900
                      SuccessMessageMixin, InitialOwnerMixin, CreateView):
901 902 903
    model = VlanGroup
    template_name = "network/vlan-group-create.html"
    form_class = VlanGroupForm
904
    success_message = _(u'Successfully created vlan group %(name)s.')
905 906


907
class VlanGroupDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
    model = VlanGroup
    template_name = "network/confirm/base_delete.html"

    def get_success_url(self):
        next = self.request.POST.get('next')
        if next:
            return next
        else:
            return reverse_lazy('network.vlan_group_list')


def remove_host_group(request, **kwargs):
    host = Host.objects.get(pk=kwargs['pk'])
    group = Group.objects.get(pk=kwargs['group_pk'])

    # for get we show the confirmation page
    if request.method == "GET":
        return render(request,
                      'network/confirm/remove_host_group.html',
                      {
                          'group': group.name,
                          'host': host.hostname
                      })

    # for post we actually remove the group from the host
    elif request.method == "POST":
        host.groups.remove(group)
935
        if not request.is_ajax():
936
            messages.success(request, _(u"Successfully removed %(host)s from "
937
                                        "%(group)s group." % {
938 939 940
                                            'host': host,
                                            'group': group
                                        }))
941 942 943 944 945 946 947 948 949 950
        return redirect(reverse_lazy('network.host',
                                     kwargs={'pk': kwargs['pk']}))


def add_host_group(request, **kwargs):
    group_pk = request.POST.get('group')
    if request.method == "POST" and group_pk:
        host = Host.objects.get(pk=kwargs['pk'])
        group = Group.objects.get(pk=group_pk)
        host.groups.add(group)
951
        if not request.is_ajax():
952
            messages.success(request, _(u"Successfully added %(host)s to group"
953
                                        " %(group)s." % {
954 955 956
                                            'host': host,
                                            'group': group
                                        }))
957
        return redirect(reverse_lazy('network.host', kwargs=kwargs))
958 959 960 961 962 963 964 965 966 967 968 969 970 971


def remove_switch_port_device(request, **kwargs):
    device = EthernetDevice.objects.get(pk=kwargs['device_pk'])
    # for get we show the confirmation page
    if request.method == "GET":
        return render(request, 'network/confirm/base_delete.html',
                      {'object': device})

    # for post we actually remove the group from the host
    elif request.method == "POST":
        device.delete()
        if not request.is_ajax():
            messages.success(request, _(u"Successfully deleted ethernet device"
972
                                        " %(name)s." % {
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
                                            'name': device.name,
                                        }))
        return redirect(reverse_lazy('network.switch_port',
                                     kwargs={'pk': kwargs['pk']}))


def add_switch_port_device(request, **kwargs):
    device_name = request.POST.get('device_name')

    if (request.method == "POST" and device_name and len(device_name) > 0
       and EthernetDevice.objects.filter(name=device_name).count() == 0):

        switch_port = SwitchPort.objects.get(pk=kwargs['pk'])
        new_device = EthernetDevice(name=device_name, switch_port=switch_port)
        new_device.save()
        if not request.is_ajax():
            messages.success(request, _(u"Successfully added %(name)s to this"
                                        " switch port" % {
                                            'name': device_name,
                                        }))
        return redirect(reverse_lazy('network.switch_port', kwargs=kwargs))

    elif not len(device_name) > 0:
996
        messages.error(request, _("Ethernet device name cannot be empty."))
997 998 999
        return redirect(reverse_lazy('network.switch_port', kwargs=kwargs))
    elif EthernetDevice.objects.get(name=device_name) is not None:
        messages.error(request, _("There is already an ethernet device with"
1000
                                  " that name."))
1001
        return redirect(reverse_lazy('network.switch_port', kwargs=kwargs))