diff --git a/conntrackt/templates/conntrackt/entity_detail.html b/conntrackt/templates/conntrackt/entity_detail.html --- a/conntrackt/templates/conntrackt/entity_detail.html +++ b/conntrackt/templates/conntrackt/entity_detail.html @@ -1,7 +1,7 @@ {% extends "conntrackt/template.html" %} {# For html_link. #} -{% load conntrackt %} +{% load conntrackt_tags %} {% block content %} {# Use a bit shorter variable names. #} @@ -20,7 +20,7 @@ {% for communication in interface.source_set.all %}
  • {{communication.destination}} - {{communication.protocol}}: {{communication.port}}
  • {% endfor %}{% endfor %} -
    iptables rules
    {% include "conntrackt/entity_iptables.html" with entity=entity %}
    {% html_link 'Download' 'entity_iptables' entity.id class="btn btn-primary" %}
    +
    iptables rules
    {{ entity_iptables }}
    {% html_link 'Download' 'entity_iptables' entity.id class="btn btn-primary" %}
    {% endif %} {% endwith %} diff --git a/conntrackt/templates/conntrackt/entity_iptables.html b/conntrackt/templates/conntrackt/entity_iptables.html --- a/conntrackt/templates/conntrackt/entity_iptables.html +++ b/conntrackt/templates/conntrackt/entity_iptables.html @@ -1,4 +1,4 @@ -{% load conntrackt %} +{% load conntrackt_tags %} # iptables rules generated by conntrackt for {{entity}} *filter :INPUT ACCEPT [0:0] diff --git a/conntrackt/templates/conntrackt/index.html b/conntrackt/templates/conntrackt/index.html --- a/conntrackt/templates/conntrackt/index.html +++ b/conntrackt/templates/conntrackt/index.html @@ -1,7 +1,7 @@ {% extends "conntrackt/template.html" %} {# For html_link #} -{% load conntrackt %} +{% load conntrackt_tags %} {% block content %}

    Welcome to Conntrackt

    diff --git a/conntrackt/templates/conntrackt/location_widget.html b/conntrackt/templates/conntrackt/location_widget.html --- a/conntrackt/templates/conntrackt/location_widget.html +++ b/conntrackt/templates/conntrackt/location_widget.html @@ -1,4 +1,4 @@ -{% load conntrackt %} +{% load conntrackt_tags %} {% for entity in entities %} diff --git a/conntrackt/templates/conntrackt/login.html b/conntrackt/templates/conntrackt/login.html --- a/conntrackt/templates/conntrackt/login.html +++ b/conntrackt/templates/conntrackt/login.html @@ -1,7 +1,7 @@ {% extends "conntrackt/template.html" %} {# For html_link #} -{% load conntrackt %} +{% load conntrackt_tags %} {% block content %} diff --git a/conntrackt/templates/conntrackt/project_detail.html b/conntrackt/templates/conntrackt/project_detail.html --- a/conntrackt/templates/conntrackt/project_detail.html +++ b/conntrackt/templates/conntrackt/project_detail.html @@ -1,6 +1,6 @@ {% extends "conntrackt/template.html" %} -{% load conntrackt %} +{% load conntrackt_tags %} {% block content %}

    {{project.name}}

    diff --git a/conntrackt/templates/conntrackt/project_widget.html b/conntrackt/templates/conntrackt/project_widget.html --- a/conntrackt/templates/conntrackt/project_widget.html +++ b/conntrackt/templates/conntrackt/project_widget.html @@ -1,4 +1,4 @@ -{% load conntrackt %} +{% load conntrackt_tags %}
    {{location.name}}{% html_link '' 'project_location_iptables' project.id location.id class="btn btn-link" %}
    {% for entity in project.entity_set.all %} diff --git a/conntrackt/templates/conntrackt/template.html b/conntrackt/templates/conntrackt/template.html --- a/conntrackt/templates/conntrackt/template.html +++ b/conntrackt/templates/conntrackt/template.html @@ -1,4 +1,4 @@ -{% load conntrackt %} +{% load conntrackt_tags %} diff --git a/conntrackt/templatetags/conntrackt.py b/conntrackt/templatetags/conntrackt_tags.py rename from conntrackt/templatetags/conntrackt.py rename to conntrackt/templatetags/conntrackt_tags.py --- a/conntrackt/templatetags/conntrackt.py +++ b/conntrackt/templatetags/conntrackt_tags.py @@ -1,12 +1,12 @@ # Import Django's template library. from django import template - # Import for determining the active URL. from django.core import urlresolvers # Get an instance of Django's template library. register = template.Library() + @register.inclusion_tag('conntrackt/html_link.html') def html_link(text, view, *args, **kwargs): """ @@ -51,6 +51,7 @@ def html_link(text, view, *args, **kwarg return context + @register.simple_tag def iptables(communication): """ @@ -70,6 +71,7 @@ def iptables(communication): return rule_template % values + @register.simple_tag(takes_context = True) def active_link(context, url_name, return_value='active', **kwargs): """ diff --git a/conntrackt/urls.py b/conntrackt/urls.py --- a/conntrackt/urls.py +++ b/conntrackt/urls.py @@ -9,7 +9,7 @@ from conntrackt.models import Entity from django.views.generic import DetailView # Import some app-specific views. -from conntrackt.views import IndexView, IptablesView, ProjectView, get_project_iptables +from conntrackt.views import IndexView, ProjectView, EntityView, entity_iptables, project_iptables urlpatterns = patterns( 'conntrackt.views', @@ -19,14 +19,14 @@ urlpatterns = patterns( url(r'^project/(?P\d+)/$', ProjectView.as_view(), name = 'project'), # View for showing information about an entity. - url(r'^entity/(?P\d+)/$', DetailView.as_view(model = Entity), + url(r'^entity/(?P\d+)/$', EntityView.as_view(), name = 'entity'), # View for rendering iptables rules for a specific entity. - url(r'^entity/(?P\d+)/iptables/$', IptablesView.as_view(), name="entity_iptables"), + url(r'^entity/(?P\d+)/iptables/$', entity_iptables, name="entity_iptables"), # View for rendering zip file with iptables rules for all entities in a project. - url(r'^project/(?P\d+)/iptables/$', get_project_iptables, name="project_iptables"), + url(r'^project/(?P\d+)/iptables/$', project_iptables, name="project_iptables"), # View for rendering zip file with iptables rules for all entities in a project for a specific location. - url(r'^project/(?P\d+)/location/(?P\d+)/iptables/$', get_project_iptables, name="project_location_iptables"), + url(r'^project/(?P\d+)/location/(?P\d+)/iptables/$', project_iptables, name="project_location_iptables"), # Views for logging-in/out the users. url(r'^login/$', login, {'template_name': 'conntrackt/login.html'}, name = "login"), url(r'^logout/$', logout, name = "logout"), diff --git a/conntrackt/utils.py b/conntrackt/utils.py new file mode 100644 --- /dev/null +++ b/conntrackt/utils.py @@ -0,0 +1,33 @@ +# Standard library imports. +import re + +# Django-specific imports. +from django.template import Context, loader + + +def generate_entity_iptables(entity): + """ + Generates full iptables rules for the supplied entity. The generated rules + can be fed directly to the iptables-restore utility. + + Arguments: + + entity - An Entity instance for which the iptables rules should be + generated. + + Returns: + + String containing the iptables rules for entity. + """ + + # Render the iptables template. + template = loader.get_template('conntrackt/entity_iptables.html') + context = Context({'entity': entity}) + content = template.render(context) + + # Remove the blank lines. + content = re.sub('^\s*\n', '', content) + content = re.sub('\n\s*\n', '\n', content) + + return content + diff --git a/conntrackt/views.py b/conntrackt/views.py --- a/conntrackt/views.py +++ b/conntrackt/views.py @@ -1,7 +1,6 @@ # For generating ZIP files. from StringIO import StringIO from zipfile import ZipFile, ZIP_DEFLATED -import re # Django-specific imports. from django.http import HttpResponse @@ -9,8 +8,10 @@ from django.shortcuts import render_to_r from django.views.generic import TemplateView, DetailView # Application-specific imports. -from conntrackt.models import Project, Entity, Location -from conntrackt.stripper import StripperMiddleware +from .models import Project, Entity, Location +from .stripper import StripperMiddleware +from .utils import generate_entity_iptables + class IndexView(TemplateView): """ @@ -35,6 +36,7 @@ class IndexView(TemplateView): return context + class ProjectView(DetailView): """ Custom view for presenting the project information. @@ -71,44 +73,64 @@ class ProjectView(DetailView): # Finally return the context. return context -class IptablesView(DetailView): + +class EntityView(DetailView): + """ + Custom view for presenting entity information. """ - Custom view for rendering iptables rules for a specific entity, and starting - automatic download by browser. + model = Entity + + def get_context_data(self, **kwargs): + """ + Returns the context data that should be used for rendering of the + template. + + Adds the 'entity_iptables' context object that contains full iptables + rules generated for the entity. + """ + + # Call the parent class method. + context = super(DetailView, self).get_context_data(**kwargs) + + # Add the rendered iptables rules to the context. + context['entity_iptables'] = generate_entity_iptables(self.object) + + return context + + +def entity_iptables(request, pk): + """ + Custom view that returns response containing iptables rules generated for an + entity. + + Makes sure to set the Content-Disposition of a response in order to + signal the browser it should start download of this view's response + immediately. Also sets the suggested filename for it. + + Arguments: + + pk - Primary key of the Entity object for which the rules should be + generated. + + Returns: + + Response object that contains the iptables rules for specified entity. """ - model = Entity - template_name = 'conntrackt/entity_iptables.html' - - def render_to_response(self, context, **kwargs): - """ - Renders the template with the given context to response. The response - will be an iptables configuration file that can be used with - iptables-restore. - - Makes sure to set the Content-Disposition of a response in order to - signal the browser it should start download of this view's response - immediately. Also sets the suggested filename for it. - """ + # Fetch the entity, and construct the response with iptables rules as + # content. + entity = get_object_or_404(Entity, pk = pk) + content = generate_entity_iptables(entity) + response = HttpResponse(content, mimetype='text/plain') + + # Add the Content-Disposition information for the browser, telling the + # browser to download the file with suggested filename. + response['Content-Disposition']="attachment; filename=%s-iptables.conf" % entity.name.lower().replace(" ", "_") - # Call the parent class method first. This will render the template. Set - # the content type to text/plain. - response = super(IptablesView, self).render_to_response(context, - content_type='text/plain', **kwargs) - - # Add the Content-Disposition information for the browser, telling the - # browser to download the file with suggested filename. - response['Content-Disposition']="attachment; filename=%s-iptables.conf" % self.object.name.lower().replace(" ", "_") + return response - # Render the response, and remove the blank lines from the template. - response.render() - response.content = re.sub('^\s*\n', '', response.content) - response.content = re.sub('\n\s*\n', '\n', response.content) - # Return the modified response. - return response - -def get_project_iptables(request, project_id, location_id = None): +def project_iptables(request, project_id, location_id = None): """ Custom view for obtaining iptables for all entities of a project or project location in a single ZIP file. @@ -143,10 +165,6 @@ def get_project_iptables(request, projec # to open the file with program as well. response = HttpResponse(mimetype='application/zip') - # Stripper middleware has to be used in order to remove the excess blank - # lines from rendering (this has to be done manually). - stripper_middleware = StripperMiddleware() - # If specific location was specified, get the entities that are part of that # project location only, otherwise fetch all of the project's entities. Also # set-up the filename that will be suggested to the browser. @@ -163,8 +181,8 @@ def get_project_iptables(request, projec # Render iptables rules for each entity, placing them in the ZIP archive. for entity in entities: - entity_iptables = stripper_middleware.process_response(request,render_to_response('conntrackt/entity_iptables.html', {'entity': entity}, mimetype="text/plain")) - zipped_iptables.writestr("%s-iptables.conf" % entity.name.lower().replace(" ", "_"), entity_iptables.content) + entity_iptables = generate_entity_iptables(entity) + zipped_iptables.writestr("%s-iptables.conf" % entity.name.lower().replace(" ", "_"), entity_iptables) # Close the archive, and flush the buffer. zipped_iptables.close()
    {% html_link project.name 'project' project.id title=project.description %}{% html_link '' 'project_iptables' project.id class="btn btn-link pull-right" %}