Changeset - f397b9db8183
[Not reviewed]
default
0 6 0
Branko Majic (branko) - 11 years ago 2013-04-14 11:37:14
branko@majic.rs
Styling updates to reflect 2SoD recommendations.
6 files changed with 49 insertions and 44 deletions:
0 comments (0 inline, 0 general)
conntrackt/admin.py
Show inline comments
 
# Import all the models from the application.
 
from conntrackt.models import *
 

	
 
# Import the administrator application.
 
# Django imports.
 
from django.contrib import admin
 
from django.core.urlresolvers import resolve
 

	
 
# Import resolver used for figuring-out the view being called in custom query
 
# calls.
 
from django.core.urlresolvers import resolve
 
# Application imports.
 
from .models import Project, Location, Entity, Interface, Communication
 

	
 

	
 
class InterfaceInline(admin.StackedInline):
 
    """
 
    This class implements the inline admin view of the Interface instances. This
 
    is used when adding the entities (since it's easier to specify interface for
 
    an entity right away).
 
@@ -21,12 +19,13 @@ class InterfaceInline(admin.StackedInlin
 
        adding/editing.
 
    """
 

	
 
    model = Interface
 
    extra = 1
 

	
 

	
 
class CommunicationAdmin(admin.ModelAdmin):
 
    """
 
    Modifies the default admin class for the Communication class. The
 
    communication class needs to be modified in a number of ways in order to
 
    cater for easier adding of communication links, letting us limit the
 
    interfaces being shown as source/destination to specific project and/or
 
@@ -78,12 +77,13 @@ class CommunicationAdmin(admin.ModelAdmi
 
            if interface_filter:
 
                kwargs["queryset"] = Interface.objects.filter(**interface_filter)
 

	
 
        # Call the parent's method so it would do any of its magic.
 
        return super(CommunicationAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
 

	
 

	
 
class EntityAdmin(admin.ModelAdmin):
 
    """
 
    This class implements the admin view of the entity instances. It adds some
 
    inline capability that can be edited for the entity, and also adds inline
 
    editing of interfaces related to the entity.
 
    """
 
@@ -94,12 +94,13 @@ class EntityAdmin(admin.ModelAdmin):
 
    list_display = ('name', 'project', 'location')
 
    # Allow the user to change project and location directly in the list.
 
    list_editable = ('project', 'location')
 
    # Enable filtering based on project and location.
 
    list_filter = ['project', 'location']
 

	
 

	
 
class InterfaceAdmin(admin.ModelAdmin):
 
    """
 
    This class implements the admin view of the interface instances. It allows
 
    editing the IP address and netmask of an interface directly in the listing.
 

	
 
    It also adds some filtering capability based on project and/or location.
 
@@ -109,12 +110,13 @@ class InterfaceAdmin(admin.ModelAdmin):
 
    list_display = ('entity', 'address', 'netmask')
 
    # Allow changing of IP address and netmask directly in the list view.
 
    list_editable = ('address', 'netmask')
 
    # Enable filtering based on project and location.
 
    list_filter = ['entity__project', 'entity__location']
 

	
 

	
 
# Register our admin classes.
 
admin.site.register(Project)
 
admin.site.register(Location)
 
admin.site.register(Entity, EntityAdmin)
 
admin.site.register(Interface, InterfaceAdmin)
 
admin.site.register(Communication, CommunicationAdmin)
conntrackt/models.py
Show inline comments
 
# Django-specific imports
 
# Django imports.
 
from django.core.exceptions import ValidationError
 
from django.db import models
 

	
 
# Create your models here.
 

	
 
class Project(models.Model):
 
    """
 
    Implements a model with information about a project. A project has some
 
    basic settings, and mainly serves the purpose of grouping entities for
 
    easier handling and administration.
 

	
 
    Fields:
 

	
 
      name - String denoting the project name.
 
      description - Free-form description of the project.
 
    """
 

	
 
    name = models.CharField(max_length = 100)
 
    description = models.TextField(blank = True)
 
    name = models.CharField(max_length=100)
 
    description = models.TextField(blank=True)
 

	
 
    def __unicode__(self):
 
        """
 
        Returns:
 
          String representation of a project.
 
        """
 

	
 
        return self.name
 

	
 

	
 
class Location(models.Model):
 
    """
 
    Implements a model with information about location. Locations can further be
 
    assigned to entities, letting the user group different servers and equipment
 
    based on location.
 

	
 
@@ -47,23 +48,24 @@ class Location(models.Model):
 
    Fields:
 

	
 
      name - String denoting the location name.
 
      description - Free-form description of a location.
 
    """
 

	
 
    name = models.CharField(max_length = 100)
 
    description = models.TextField(blank = True)
 
    name = models.CharField(max_length=100)
 
    description = models.TextField(blank=True)
 

	
 
    def __unicode__(self):
 
        """
 
        Returns:
 
          String representation of a location.
 
        """
 

	
 
        return self.name
 

	
 

	
 
class Entity(models.Model):
 
    """
 
    Models an entity in a project. An entity can be a server, router, or any
 
    other piece of networking equipment that has its own IP address.
 

	
 
    Entities can also be used for representing subnets etc. This is useful when
 
@@ -78,14 +80,14 @@ class Entity(models.Model):
 
      project - Foreign key pointing to the project to which the entity
 
      belongs.
 
      location - Foreign key pointing to the location at which the entity is
 
      located.
 
    """
 

	
 
    name = models.CharField(max_length = 100)
 
    description = models.TextField(blank = True)
 
    name = models.CharField(max_length=100)
 
    description = models.TextField(blank=True)
 
    project = models.ForeignKey(Project)
 
    location = models.ForeignKey(Location)
 

	
 
    class Meta:
 
        """
 
        Overrides some of the default parameters used by Django for this model.
 
@@ -103,12 +105,13 @@ class Entity(models.Model):
 
          String representation of an entity. This identifier contains name of
 
          entity, its project name, and location name.
 
        """
 

	
 
        return "%s (%s - %s)" % (self.name, self.project, self.location)
 

	
 

	
 
class Interface(models.Model):
 
    """
 
    Models a representation of an interface on an entity. It can be used for
 
    representing the subnets as well.
 

	
 
    Each interface is coupled with a specific Entity.
 
@@ -123,17 +126,17 @@ class Interface(models.Model):
 
      address in it as well.
 
      netmask - Netmask of the interface. By default this is /32
 
      (255.255.255.255), but in case of subnet entities this can be used for
 
      denoting the network netmask.
 
    """
 

	
 
    name = models.CharField(max_length = 100, default = 'eth0')
 
    description = models.TextField(blank = True, default = 'Main network interface.')
 
    name = models.CharField(max_length=100, default='eth0')
 
    description = models.TextField(blank=True, default='Main network interface.')
 
    entity = models.ForeignKey(Entity)
 
    address = models.IPAddressField()
 
    netmask = models.IPAddressField(default = '255.255.255.255')
 
    netmask = models.IPAddressField(default='255.255.255.255')
 

	
 
    def __unicode__(self):
 
        """
 
        Returns:
 
          String representation of an interface. In case of single IP this will
 
          simply be the interface name and IP address. In case of subnet it will
 
@@ -142,12 +145,13 @@ class Interface(models.Model):
 

	
 
        if self.netmask == '255.255.255.255':
 
            return '%s (%s)' % (self.entity.name, self.address)
 
        else:
 
            return '%s (%s/%s)' % (self.entity.name, self.address, self.netmask)
 

	
 

	
 
class Communication(models.Model):
 
    """
 
    Models a representation of allowed network communication. This lets the user
 
    display the possible network connections that should be allowed. Information
 
    from the communication instances is also used for generating the iptables
 
    rules for the entities.
 
@@ -180,17 +184,17 @@ class Communication(models.Model):
 
    PROTOCOL_CHOICES = (
 
        ('TCP', 'TCP'),
 
        ('UDP', 'UDP'),
 
        ('ICMP', 'ICMP'),
 
        )
 

	
 
    source = models.ForeignKey(Interface, related_name = 'source_set')
 
    destination = models.ForeignKey(Interface, related_name = 'destination_set')
 
    protocol = models.CharField(max_length = 10, choices = PROTOCOL_CHOICES)
 
    port = models.IntegerField(default = 0)
 
    description = models.TextField(blank = True)
 
    source = models.ForeignKey(Interface, related_name='source_set')
 
    destination = models.ForeignKey(Interface, related_name='destination_set')
 
    protocol = models.CharField(max_length=10, choices=PROTOCOL_CHOICES)
 
    port = models.IntegerField(default=0)
 
    description = models.TextField(blank=True)
 

	
 
    def __unicode__(self):
 
        """
 
        Returns:
 
          String representation of an interface. This involves showing the
 
          source and destination _entity_ name, protocol, and port.
conntrackt/templatetags/conntrackt_tags.py
Show inline comments
 
# Import Django's template library.
 
# Django imports.
 
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):
 
@@ -69,13 +69,13 @@ def iptables(communication):
 
    elif communication.protocol in ('ICMP'):
 
        rule_template = "-A INPUT -s %s/%s -p %s -m %s --icmp-type %s -j ACCEPT"
 

	
 
    return rule_template % values
 

	
 

	
 
@register.simple_tag(takes_context = True)
 
@register.simple_tag(takes_context=True)
 
def active_link(context, url_name, return_value='active', **kwargs):
 
    """
 
    This template tag can be used to check if the provided URL matches against
 
    the path from the request or not.
 

	
 
    Arguments:
conntrackt/urls.py
Show inline comments
 
# Import basic functions for URL pattern processing.
 
# Django imports.
 
from django.conf.urls import patterns, url
 

	
 
# For logging-in the users
 
from django.contrib.auth.views import login, logout
 

	
 
# Import some app-specific views.
 
# Application imports.
 
from .views import IndexView, ProjectView, EntityView, entity_iptables, project_iptables
 

	
 

	
 
urlpatterns = patterns(
 
    'conntrackt.views',
 
    # Homepage/index view.
 
    url(r'^$', IndexView.as_view(), name="index"),
 
    # View for showing information about a project.
 
    url(r'^project/(?P<pk>\d+)/$', ProjectView.as_view(),
 
        name = 'project'),
 
        name='project'),
 
    # View for showing information about an entity.
 
    url(r'^entity/(?P<pk>\d+)/$', EntityView.as_view(),
 
        name = 'entity'),
 
        name='entity'),
 
    # View for rendering iptables rules for a specific entity.
 
    url(r'^entity/(?P<pk>\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<project_id>\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<project_id>\d+)/location/(?P<location_id>\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"),
 
    url(r'^login/$', login, {'template_name': 'conntrackt/login.html'}, name="login"),
 
    url(r'^logout/$', logout, name="logout"),
 
)
 

	
conntrackt/utils.py
Show inline comments
 
# Standard library imports.
 
import re
 

	
 
# Django-specific imports.
 
# Django imports.
 
from django.template import Context, loader
 

	
 

	
 
def generate_entity_iptables(entity):
 
    """
 
    Generates full iptables rules for the supplied entity. The generated rules
conntrackt/views.py
Show inline comments
 
# For generating ZIP files.
 
# Standard library imports.
 
from StringIO import StringIO
 
from zipfile import ZipFile, ZIP_DEFLATED
 

	
 
# Django-specific imports.
 
# Django imports.
 
from django.http import HttpResponse
 
from django.shortcuts import render_to_response, get_object_or_404
 
from django.views.generic import TemplateView, DetailView
 

	
 
# Application-specific imports.
 
# Application imports.
 
from .models import Project, Entity, Location
 
from .utils import generate_entity_iptables
 

	
 

	
 
class IndexView(TemplateView):
 
    """
 
@@ -59,14 +59,14 @@ class ProjectView(DetailView):
 

	
 
        # Set-up an array that will contaion (location, entities) tuples.
 
        location_entities = []
 

	
 
        # Add the (location, entities) tuple for each location that has entities
 
        # belonging to the related project.
 
        for location in Location.objects.filter(entity__project = self.object).distinct():
 
            entities = Entity.objects.filter(project = self.object, location = location)
 
        for location in Location.objects.filter(entity__project=self.object).distinct():
 
            entities = Entity.objects.filter(project=self.object, location=location)
 
            location_entities.append((location, entities))
 

	
 
        # Add the (location, entities) tuples to context.
 
        context['location_entities'] = location_entities
 

	
 
        # Finally return the context.
 
@@ -115,24 +115,24 @@ def entity_iptables(request, pk):
 

	
 
        Response object that contains the iptables rules for specified entity.
 
    """
 

	
 
    # Fetch the entity, and construct the response with iptables rules as
 
    # content.
 
    entity = get_object_or_404(Entity, pk = pk)
 
    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(" ", "_")
 

	
 
    return response
 

	
 

	
 
def 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.
 

	
 
    Arguments:
 

	
 
@@ -149,13 +149,13 @@ def project_iptables(request, project_id
 

	
 
        Response object that contains the ZIP file and Content-Disposition
 
        information.
 
    """
 

	
 
    # Fetch the project.
 
    project = get_object_or_404(Project, pk = project_id)
 
    project = get_object_or_404(Project, pk=project_id)
 

	
 
    # Set-up a string IO object to which we'll write the ZIP file (in-memory).
 
    buff = StringIO()
 

	
 
    # Create a new ZIP file in-memory.
 
    zipped_iptables = ZipFile(buff, "w", ZIP_DEFLATED)
 
@@ -166,13 +166,13 @@ def project_iptables(request, project_id
 

	
 
    # 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.
 
    if location_id:
 
        location = get_object_or_404(Location, pk=location_id)
 
        entities = project.entity_set.filter(location = location)
 
        entities = project.entity_set.filter(location=location)
 
        filename = '%s_%s-iptables.zip' % (project.name, location.name)
 
    else:
 
        entities = project.entity_set.all()
 
        filename = '%s-iptables.zip' % (project.name)
 

	
 
    # Lower-case the filename, and replace spaces with underscores (_).
0 comments (0 inline, 0 general)