Added templates. Moved functionality out of models
authorLeonidas Poulopoulos <leopoul@noc.grnet.gr>
Sun, 20 Nov 2011 07:47:28 +0000 (09:47 +0200)
committerLeonidas Poulopoulos <leopoul@noc.grnet.gr>
Sun, 20 Nov 2011 07:47:28 +0000 (09:47 +0200)
flowspec/admin.py
flowspec/models.py
flowspec/views.py
urls.py

index 13ece6d..283bd64 100644 (file)
@@ -1,5 +1,29 @@
 from django.contrib import admin
 from flowspy.flowspec.models import *
+from utils import proxy as PR
+
+class RouteAdmin(admin.ModelAdmin):
+    
+    actions = ['deactivate']
+
+    def deactivate(self, request, queryset):
+        applier = PR.Applier(route_objects=queryset)
+        commit, response = applier.apply(configuration=applier.delete_routes())
+        if commit:
+            rows = queryset.update(is_online=False)
+            queryset.update(response="Successfully removed route from network")
+            self.message_user(request, "Successfully removed %s routes from network" % rows)
+        else:
+            self.message_user(request, "Could not remove routes from network")
+    deactivate.short_description = "Remove selected routes from network"
+
+    list_display = ('name', 'get_match', 'get_then', 'is_online', 'applier', 'response')
+    fields = ('name', 'match','then','applier', 'expires')
+
+    #def formfield_for_dbfield(self, db_field, **kwargs):
+    #    if db_field.name == 'password':
+    #        kwargs['widget'] = PasswordInput
+    #    return db_field.formfield(**kwargs)
 
 admin.site.register(MatchAddress)
 admin.site.register(MatchPort)
@@ -13,4 +37,8 @@ admin.site.register(MatchTcpFlag)
 admin.site.register(ThenAction)
 admin.site.register(ThenStatement)
 admin.site.register(MatchStatement)
-admin.site.register(Route)
+admin.site.register(Route, RouteAdmin)
+
+admin.site.disable_action('delete_selected')
+
+
index cf69432..983d698 100644 (file)
@@ -3,12 +3,15 @@
 
 from django.db import models
 from django.contrib.auth.models import User
-
-import nxpy as np
-from ncclient import manager
-from ncclient.transport.errors import AuthenticationError, SSHError
-from lxml import etree as ET
+from utils import proxy as PR
 from ipaddr import *
+import logging
+
+FORMAT = '%(asctime)s %(levelname)s: %(message)s'
+logging.basicConfig(format=FORMAT)
+logger = logging.getLogger(__name__)
+logger.setLevel(logging.DEBUG)
+
 
 FRAGMENT_CODES = (
     ("dont-fragment", "Don't fragment"),
@@ -38,7 +41,8 @@ class MatchAddress(models.Model):
     def clean(self, *args, **kwargs):
         from django.core.exceptions import ValidationError
         try:
-            assert(IPNetwork(self.address))
+            address = IPNetwork(self.address)
+            self.address = address.exploded
         except Exception:
             raise ValidationError('Invalid network address format')
 
@@ -108,7 +112,7 @@ class ThenAction(models.Model):
 class ThenStatement(models.Model):
     thenaction = models.ManyToManyField(ThenAction)
     class Meta:
-        db_table = u'then'    
+        db_table = u'then'
 
 class MatchStatement(models.Model):
     matchDestination = models.ForeignKey(MatchAddress, blank=True, null=True, related_name="matchDestination")
@@ -123,7 +127,7 @@ class MatchStatement(models.Model):
     matchSource = models.ForeignKey(MatchAddress, blank=True, null=True, related_name="matchSource")
     matchSourcePort = models.ManyToManyField(MatchPort, blank=True, null=True, related_name="matchSourcePort")
     matchTcpFlag = models.ForeignKey(MatchTcpFlag, blank=True, null=True)
-    
+
 #    def clean(self, *args, **kwargs):
 #        clean_error = True
 #        from django.core.exceptions import ValidationError
@@ -164,7 +168,11 @@ class Route(models.Model):
     then = models.ForeignKey(ThenStatement)
     filed = models.DateTimeField(auto_now_add=True)
     last_updated = models.DateTimeField(auto_now=True)
+    is_online = models.BooleanField(default=False)
     expires = models.DateTimeField()
+    response = models.CharField(max_length=512, blank=True, null=True)
+
+    
     def __unicode__(self):
         return self.name
     
@@ -172,45 +180,151 @@ class Route(models.Model):
         db_table = u'route'
         
     def save(self, *args, **kwargs):
-        # Begin translation to device xml configuration
-        device = np.Device()
-        flow = np.Flow()
-        route = np.Route()
-        flow.routes.append(route)
-        device.routing_options.append(flow)
-        route.name = self.name
+        applier = PR.Applier(route_object=self)
+        commit, response = applier.apply()
+        if commit:
+            self.is_online = True
+            self.response = response
+        else:
+            self.is_online = False
+            self.response = response
+        super(Route, self).save(*args, **kwargs)
+    
+    def is_synced(self):
+        
+        found = False
+        get_device = PR.Retriever()
+        device = get_device.fetch_device()
+        try:
+            routes = device.routing_options[0].routes
+        except Exception as e:
+            logger.error("No routing options on device. Exception: %s" %e)
+            return False
+        for route in routes:
+            if route.name == self.name:
+                found = True
+                logger.info('Found a matching route name')
+                devicematch = route.match
+                routematch = self.match
+                try:
+                    assert(routematch.matchDestination.address)
+                    assert(devicematch['destination'][0])
+                    if routematch.matchDestination.address == devicematch['destination'][0]:
+                        found = found and True
+                        logger.info('Found a matching destination')
+                    else:
+                        found = False
+                        logger.info('Destination fields do not match')
+                except:
+                    pass
+                try:
+                    assert(routematch.matchSource.address)
+                    assert(devicematch['source'][0])
+                    if routematch.matchSource.address == devicematch['source'][0]:
+                        found = found and True
+                        logger.info('Found a matching source')
+                    else:
+                        found = False
+                        logger.info('Source fields do not match')
+                except:
+                    pass
+                try:
+                    assert(routematch.matchfragmenttype.fragmenttype)
+                    assert(devicematch['fragment'][0])
+                    if routematch.matchfragmenttype.fragmenttype == devicematch['fragment'][0]:
+                        found = found and True
+                        logger.info('Found a matching fragment type')
+                    else:
+                        found = False
+                        logger.info('Fragment type fields do not match')
+                except:
+                    pass
+                try:
+                    assert(routematch.matchicmpcode.icmp_code)
+                    assert(devicematch['icmp-code'][0])
+                    if routematch.matchicmpcode.icmp_code == devicematch['icmp-code'][0]:
+                        found = found and True
+                        logger.info('Found a matching icmp code')
+                    else:
+                        found = False
+                        logger.info('Icmp code fields do not match')
+                except:
+                    pass
+                try:
+                    assert(routematch.matchicmptype.icmp_type)
+                    assert(devicematch['icmp-type'][0])
+                    if routematch.matchicmpcode.icmp_type == devicematch['icmp-type'][0]:
+                        found = found and True
+                        logger.info('Found a matching icmp type')
+                    else:
+                        found = False
+                        logger.info('Icmp type fields do not match')
+                except:
+                    pass
+                try:
+                    assert(routematch.matchprotocol.protocol)
+                    assert(devicematch['protocol'][0])
+                    if routematch.matchprotocol.protocol == devicematch['protocol'][0]:
+                        found = found and True
+                        logger.info('Found a matching protocol')
+                    else:
+                        found = False
+                        logger.info('Protocol fields do not match')
+                except:
+                    pass
+                if found and not self.is_online:
+                     logger.error('Rule is applied on device but appears as offline')
+                     found = False
+        
+        return found
+
+    
+    def get_then(self):
+        ret = ''
+        then_statements = self.then.thenaction.all()
+        for statement in then_statements:
+            if statement.action_value:
+                ret = "%s %s:<strong>%s</strong><br/>" %(ret, statement.action, statement.action_value)
+            else: 
+                ret = "%s %s<br>" %(ret, statement.action)
+        return ret.rstrip(',')
+    
+    get_then.short_description = 'Then statement'
+    get_then.allow_tags = True
+
+    def get_match(self):
+        ret = ''
         match = self.match
-        if match.matchSource:
-            route.match['source'].append(match.matchSource.address)
         if match.matchDestination:
-            route.match['destination'].append(match.matchDestination.address)
+            ret = ret = '%s Destination Address:<strong>%s</strong><br/>' %(ret, match.matchDestination)
+        if match.matchfragmenttype:
+            ret = ret = "%s Fragment Type:<strong>%s</strong><br/>" %(ret, match.matchfragmenttype)
+        if match.matchicmpcode:
+            ret = ret = "%s ICMP code:<strong>%s</strong><br/>" %(ret, match.matchicmpcode)
+        if match.matchicmptype:
+            ret = ret = "%s ICMP Type:<strong>%s</strong><br/>" %(ret, match.matchicmptype)
+        if match.matchpacketlength:
+            ret = ret = "%s Packet Length:<strong>%s</strong><br/>" %(ret, match.matchpacketlength)
         if match.matchprotocol:
-            route.match['protocol'].append(match.matchprotocol.protocol)
+            ret = ret = "%s Protocol:<strong>%s</strong><br/>" %(ret, match.matchprotocol)
+        if match.matchSource:
+            ret = ret = "%s Source Address:<strong>%s</strong><br/>" %(ret, match.matchSource)
+        if match.matchTcpFlag:
+            ret = ret = "%s TCP flag:<strong>%s</strong><br/>" %(ret, match.matchTcpFlag)
         if match.matchport:
             for port in match.matchport.all():
-                route.match['port'].append(port.port)
+                    ret = "%s Port:<strong>%s</strong><br/>" %(ret, port)
         if match.matchDestinationPort:
             for port in match.matchDestinationPort.all():
-                route.match['destination-port'].append(port.port)
+                    ret = "%s Port:<strong>%s</strong><br/>" %(ret, port)
         if match.matchSourcePort:
             for port in match.matchSourcePort.all():
-                route.match['source-port'].append(port.port)
-        if match.matchicmpcode:
-            route.match['icmp-code'].append(match.matchicmpcode.icmp_code)
-        if match.matchicmptype:
-            route.match['icmp-type'].append(match.matchicmptype.icmp_type)
-        if match.matchTcpFlag:
-            route.match['tcp-flags'].append(match.matchTcpFlag.tcp_flags)
+                    ret = "%s Port:<strong>%s</strong><br/>" %(ret, port)
         if match.matchdscp:
             for dscp in match.matchdscp.all():
-                route.match['dscp'].append(dscp.dscp)
-        if match.matchfragmenttype:
-            route.match['fragment'].append(match.matchfragmenttype.fragmenttype)
-        then = self.then
-        for thenaction in then.thenaction.all():
-            if thenaction.action_value:
-                route.then[thenaction.action] = thenaction.action_value
-            else:
-                route.then[thenaction.action] = True
-        print ET.tostring(device.export())
-        super(Route, self).save(*args, **kwargs)
\ No newline at end of file
+                    ret = "%s Port:<strong>%s</strong><br/>" %(ret, dscp)
+        return ret.rstrip('<br/>')
+        
+    get_match.short_description = 'Match statement'
+    get_match.allow_tags = True
+
index 60f00ef..77ae75a 100644 (file)
@@ -1 +1,28 @@
 # Create your views here.
+import urllib2
+import re
+import socket
+from django import forms
+from django.core.cache import cache
+from django.views.decorators.csrf import csrf_exempt
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
+from django.shortcuts import get_object_or_404, render_to_response
+from django.core.context_processors import request
+from django.template.context import RequestContext
+from django.template.loader import get_template
+from django.utils import simplejson
+from django.core.urlresolvers import reverse
+from django.contrib import messages
+
+from flowspy.flowspec.models import *
+
+def user_routes(request):
+    if request.user.is_anonymous():
+        return HttpResponseRedirect(reverse('login'))
+    user_routes = Route.objects.filter(applier=request.user)
+    print user_routes
+    return render_to_response('user_routes.html', {'routes': user_routes},
+                              context_instance=RequestContext(request))
+
+
diff --git a/urls.py b/urls.py
index 32ffb38..7fa8548 100644 (file)
--- a/urls.py
+++ b/urls.py
@@ -1,5 +1,5 @@
 from django.conf.urls.defaults import *
-
+from django.conf import settings
 # Uncomment the next two lines to enable the admin:
 from django.contrib import admin
 admin.autodiscover()
@@ -7,10 +7,20 @@ admin.autodiscover()
 urlpatterns = patterns('',
     # Example:
     # (r'^flowspy/', include('flowspy.foo.urls')),
-
+    url(r'^/?$', 'flowspy.flowspec.views.user_routes', name="user-routes"),
+    url(r'^user/login/?', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name="login"),
+    url(r'^user/logout/?', 'django.contrib.auth.views.logout', {'next_page': '/'}, name="logout"),
+    (r'^setlang/?$', 'django.views.i18n.set_language'),
     # Uncomment the admin/doc line below to enable admin documentation:
     (r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
     # Uncomment the next line to enable the admin:
     (r'^admin/', include(admin.site.urls)),
 )
+
+
+if settings.DEBUG:
+    urlpatterns += patterns('',
+        (r'^static/(?P<path>.*)', 'django.views.static.serve',\
+            {'document_root':  settings.STATIC_URL}),
+    )
\ No newline at end of file