from django.views.generic import (TemplateView, UpdateView, DeleteView, CreateView) from django.core.urlresolvers import reverse_lazy from django.shortcuts import render, redirect from django.http import HttpResponse from django_tables2 import SingleTableView from firewall.models import (Host, Vlan, Domain, Group, Record, Blacklist, Rule, VlanGroup, SwitchPort, EthernetDevice) from .tables import (HostTable, VlanTable, SmallHostTable, DomainTable, GroupTable, RecordTable, BlacklistTable, RuleTable, VlanGroupTable, SmallRuleTable, SmallGroupRuleTable, SmallRecordTable, SwitchPortTable) from .forms import (HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistForm, RuleForm, VlanGroupForm, SwitchPortForm) from django.contrib import messages from django.views.generic.edit import FormMixin from django.utils.translation import ugettext_lazy as _ # from django.db.models import Q from operator import itemgetter from itertools import chain import json class SuccessMessageMixin(FormMixin): """ Adds a success message on successful form submission. From django/contrib/messages/views.py@9a85ad89 """ success_message = '' def form_valid(self, form): response = super(SuccessMessageMixin, self).form_valid(form) success_message = self.get_success_message(form.cleaned_data) if success_message: messages.success(self.request, success_message) return response def get_success_message(self, cleaned_data): return self.success_message % cleaned_data class IndexView(TemplateView): template_name = "network/index.html" def get_context_data(self, **kwargs): context = super(IndexView, self).get_context_data(**kwargs) size = 13 blacklists = Blacklist.objects.all().order_by('-modified_at')[:size] 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 class BlacklistList(SingleTableView): model = Blacklist table_class = BlacklistTable template_name = "network/blacklist-list.html" table_pagination = False class BlacklistDetail(UpdateView, SuccessMessageMixin): model = Blacklist template_name = "network/blacklist-edit.html" form_class = BlacklistForm success_message = _(u'Successfully modified blacklist ' '%(ipv4)s - %(type)s!') 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 class BlacklistCreate(CreateView, SuccessMessageMixin): model = Blacklist template_name = "network/blacklist-create.html" form_class = BlacklistForm success_message = _(u'Successfully created blacklist ' '%(ipv4)s - %(type)s!') class BlacklistDelete(DeleteView): model = Blacklist 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: to_delete = Blacklist.objects.get(pk=self.kwargs['pk']) context['object'] = "%s - %s - %s" % (to_delete.ipv4, to_delete.reason, to_delete.type) 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') class DomainList(SingleTableView): model = Domain table_class = DomainTable template_name = "network/domain-list.html" table_pagination = False class DomainDetail(UpdateView, SuccessMessageMixin): model = Domain template_name = "network/domain-edit.html" form_class = DomainForm success_message = _(u'Successfully modified domain %(name)s!') 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) context['domain_pk'] = self.get_object().pk # records q = Record.objects.filter(domain=self.get_object()).all() context['record_list'] = SmallRecordTable(q) return context class DomainCreate(CreateView, SuccessMessageMixin): model = Domain template_name = "network/domain-create.html" form_class = DomainForm success_message = _(u'Successfully created domain %(name)s!') class DomainDelete(DeleteView): 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'): messages.error(request, _(u"Object name does not match!")) return self.get(request, *args, **kwargs) response = super(DomainDelete, self).delete(request, *args, **kwargs) messages.success(request, _(u"Domain successfully deleted!")) return response def get_context_data(self, **kwargs): context = super(DomainDelete, self).get_context_data(**kwargs) records_from_hosts = _(u'Records from hosts') deps = [] # vlans vlans = Vlan.objects.filter(domain=self.object).all() if len(vlans) > 0: deps.append({ 'name': _('Vlans'), 'data': vlans }) # hosts hosts = Host.objects.filter(vlan__in=deps[0]['data']) if len(hosts) > 0: deps.append({ 'name': _('Hosts'), 'data': hosts }) # records records = Record.objects.filter( host__in=deps[1]['data'] # Q(domain=self.object) | (host__in=deps[1]['data']) ) if len(records) > 0: deps.append({ 'name': records_from_hosts, 'data': records }) 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) n = indexes.index(records_from_hosts) if len(indexes) > 0 else 0 deps.append({ 'name': u'Records only from the domain', 'data': records.exclude(pk__in=deps[n]['data']) if n > 0 else records }) context['deps'] = deps context['confirmation'] = True return context class GroupList(SingleTableView): model = Group table_class = GroupTable template_name = "network/group-list.html" table_pagination = False class GroupCreate(CreateView, SuccessMessageMixin): model = Group template_name = "network/group-create.html" form_class = GroupForm success_message = _(u'Successfully created host group %(name)s!') class GroupDetail(UpdateView, SuccessMessageMixin): model = Group template_name = "network/group-edit.html" form_class = GroupForm success_message = _(u'Successfully modified host group %(name)s!') def get_success_url(self): if 'pk' in self.kwargs: return reverse_lazy('network.group', kwargs=self.kwargs) def get_context_data(self, *args, **kwargs): context = super(GroupDetail, self).get_context_data(**kwargs) context['group_pk'] = self.object.pk # records q = Rule.objects.filter(hostgroup=self.object) context['rule_list'] = SmallRuleTable(q) return context class GroupDelete(DeleteView): 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 class HostList(SingleTableView): 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: data = Host.objects.filter(vlan=vlan_id).select_related() else: data = Host.objects.select_related() return data class HostDetail(UpdateView, SuccessMessageMixin): model = Host template_name = "network/host-edit.html" form_class = HostForm success_message = _(u'Successfully modified host %(hostname)s!') def get(self, request, *args, **kwargs): if request.is_ajax(): host = Host.objects.get(pk=kwargs['pk']) host = { 'hostname': host.hostname, 'ipv4': host.ipv4, 'ipv6': host.ipv6, 'fqdn': host.get_fqdn() } return HttpResponse(json.dumps(host), content_type="application/json") else: self.object = self.get_object() return super(HostDetail, self).get(request, *args, **kwargs) 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'] return context def get_success_url(self): if 'pk' in self.kwargs: return reverse_lazy('network.host', kwargs=self.kwargs) class HostCreate(CreateView, SuccessMessageMixin): model = Host template_name = "network/host-create.html" form_class = HostForm success_message = _(u'Successfully created host %(hostname)s!') class HostDelete(DeleteView): 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({ 'name': _('Records'), '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'): messages.error(request, _(u"Object name does not match!")) return self.get(request, *args, **kwargs) response = super(HostDelete, self).delete(request, *args, **kwargs) messages.success(request, _(u"Host successfully deleted!")) return response class RecordList(SingleTableView): model = Record table_class = RecordTable template_name = "network/record-list.html" table_pagination = False 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 class RecordDetail(UpdateView, SuccessMessageMixin): model = Record template_name = "network/record-edit.html" form_class = RecordForm # TODO fqdn success_message = _(u'Successfully modified record!') 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) class RecordCreate(CreateView, SuccessMessageMixin): model = Record template_name = "network/record-create.html" form_class = RecordForm # TODO fqdn success_message = _(u'Successfully created record!') def get_initial(self): return { # 'owner': 1, 'domain': self.request.GET.get('domain'), } class RecordDelete(DeleteView): 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') class RuleList(SingleTableView): model = Rule table_class = RuleTable template_name = "network/rule-list.html" table_pagination = False class RuleDetail(UpdateView, SuccessMessageMixin): model = Rule template_name = "network/rule-edit.html" form_class = RuleForm success_message = _(u'Successfully modified rule!') 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 class RuleCreate(CreateView, SuccessMessageMixin): model = Rule template_name = "network/rule-create.html" form_class = RuleForm success_message = _(u'Successfully created rule!') def get_initial(self): return { # 'owner': 1, 'host': self.request.GET.get('host'), 'hostgroup': self.request.GET.get('hostgroup') } class RuleDelete(DeleteView): 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') class SwitchPortList(SingleTableView): model = SwitchPort table_class = SwitchPortTable template_name = "network/switch-port-list.html" table_pagination = False class SwitchPortDetail(UpdateView, SuccessMessageMixin): model = SwitchPort template_name = "network/switch-port-edit.html" form_class = SwitchPortForm success_message = _(u'Succesfully modified switch port!') 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 class SwitchPortCreate(CreateView, SuccessMessageMixin): model = SwitchPort template_name = "network/switch-port-create.html" form_class = SwitchPortForm success_message = _(u'Successfully created switch port!') class SwitchPortDelete(DeleteView): 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') class VlanList(SingleTableView): model = Vlan table_class = VlanTable template_name = "network/vlan-list.html" table_pagination = False class VlanDetail(UpdateView, SuccessMessageMixin): model = Vlan template_name = "network/vlan-edit.html" form_class = VlanForm slug_field = 'vid' slug_url_kwarg = 'vid' success_message = _(u'Succesfully modified vlan %(name)s!') def get_context_data(self, **kwargs): context = super(VlanDetail, self).get_context_data(**kwargs) q = Host.objects.filter(vlan=self.object).all() context['host_list'] = SmallHostTable(q) context['vlan_vid'] = self.kwargs.get('vid') return context success_url = reverse_lazy('network.vlan_list') class VlanCreate(CreateView, SuccessMessageMixin): model = Vlan template_name = "network/vlan-create.html" form_class = VlanForm success_message = _(u'Successfully created vlan %(name)s!') class VlanDelete(DeleteView): 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'): messages.error(request, _(u"Object name does not match!")) return self.get(request, *args, **kwargs) response = super(VlanDelete, self).delete(request, *args, **kwargs) messages.success(request, _(u"Vlan successfully deleted!")) 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({ 'name': _('Hosts'), 'data': hosts }) # records records = Record.objects.filter(host__in=deps[0]['data']) if len(records) > 0: deps.append({ 'name': _('Records'), 'data': records }) context['deps'] = deps context['confirmation'] = True return context class VlanGroupList(SingleTableView): model = VlanGroup table_class = VlanGroupTable template_name = "network/vlan-group-list.html" table_pagination = False class VlanGroupDetail(UpdateView, SuccessMessageMixin): model = VlanGroup template_name = "network/vlan-group-edit.html" form_class = VlanGroupForm success_url = reverse_lazy('network.vlan_group_list') success_message = _(u'Successfully modified vlan group %(name)s!') def get_context_data(self, *args, **kwargs): context = super(VlanGroupDetail, self).get_context_data(**kwargs) context['vlangroup_pk'] = self.object.pk return context class VlanGroupCreate(CreateView, SuccessMessageMixin): model = VlanGroup template_name = "network/vlan-group-create.html" form_class = VlanGroupForm success_message = _(u'Successfully created vlan group %(name)s!') class VlanGroupDelete(DeleteView): 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) if not request.is_ajax(): messages.success(request, _(u"Successfully removed %(host)s from " "%(group)s group!" % { 'host': host, 'group': group })) 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) if not request.is_ajax(): messages.success(request, _(u"Successfully added %(host)s to group" " %(group)s!" % { 'host': host, 'group': group })) return redirect(reverse_lazy('network.host', kwargs=kwargs)) 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" " %(name)s!" % { '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: messages.error(request, _("Ethernet device name cannot be empty!")) 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" " that name!")) return redirect(reverse_lazy('network.switch_port', kwargs=kwargs))