|
@@ -17,16 +17,19 @@
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
# Django Conntrackt. If not, see <http://www.gnu.org/licenses/>.
|
|
|
#
|
|
|
|
|
|
|
|
|
# Django imports.
|
|
|
from django.contrib.admin.util import NestedObjects
|
|
|
from django.core.exceptions import ValidationError
|
|
|
from django.core.urlresolvers import reverse
|
|
|
from django.db import models
|
|
|
from django.db.models.query_utils import Q
|
|
|
from django.utils.html import format_html
|
|
|
from django.utils.text import capfirst
|
|
|
|
|
|
|
|
|
class SearchManager(models.Manager):
|
|
|
"""
|
|
|
Custom model manager that implements search for model instances that contain
|
|
|
a specific string (search term) in fields "name" or "description".
|
|
@@ -44,13 +47,100 @@ class SearchManager(models.Manager):
|
|
|
Query set with model instances that matched the search.
|
|
|
"""
|
|
|
|
|
|
return self.filter(Q(name__icontains=search_term) | Q(description__icontains=search_term))
|
|
|
|
|
|
|
|
|
class Project(models.Model):
|
|
|
class RelatedCollectorMixin(object):
|
|
|
"""
|
|
|
Implements model mixin for easily obtainning related items of a model
|
|
|
instance.
|
|
|
|
|
|
The mixin can be used for obtaining all model objects that are directly or
|
|
|
indirectly linked to the calling model object (through foreign key
|
|
|
relationships).
|
|
|
|
|
|
This mixin is very useful in delete views for warning the user about all of
|
|
|
the related items that will be deleted if the calling item is deleted as
|
|
|
well.
|
|
|
"""
|
|
|
|
|
|
def get_dependant_objects(self):
|
|
|
"""
|
|
|
Creates a list of model objects that depend (reference), both directly
|
|
|
and indirectly, on calling model object. The calling model object is
|
|
|
included as the first element of the list. This method call can be used
|
|
|
in order to obtain a list of model objects that would get deleted in
|
|
|
case the calling model object gets deleted.
|
|
|
|
|
|
Returns:
|
|
|
Nested list of model objects that depend (reference) calling model
|
|
|
object.
|
|
|
"""
|
|
|
|
|
|
collector = NestedObjects(using='default')
|
|
|
|
|
|
collector.collect([self])
|
|
|
|
|
|
return collector.nested()
|
|
|
|
|
|
def get_dependant_objects_representation(self):
|
|
|
"""
|
|
|
Creates a nested list of object representations that depend (reference),
|
|
|
both directly and indirectly, calling model object. This method call can
|
|
|
be used in order to obtain a list of string representations of model
|
|
|
objects that would get deleted in case the calling model object gets
|
|
|
deleted.
|
|
|
|
|
|
The resulting nested list can be shown to the user for
|
|
|
warning/notification purposes using the unordered_list template tag.
|
|
|
|
|
|
Each non-list element will be a string of format:
|
|
|
|
|
|
MODEL_NAME: OBJECT_REPRESENTATION
|
|
|
|
|
|
If object has a callable get_absolute_url method, the object
|
|
|
representation will be surrouned by HTML anchor tag (<a></a>) where
|
|
|
target (href) is set to the value of get_absolute_url() method call.
|
|
|
|
|
|
Returns:
|
|
|
Nested list of representations of model objects that depend
|
|
|
(reference) calling model object.
|
|
|
"""
|
|
|
|
|
|
collector = NestedObjects(using='default')
|
|
|
|
|
|
collector.collect([self])
|
|
|
|
|
|
def formatter_callback(obj):
|
|
|
"""
|
|
|
Creates model object representation in format:
|
|
|
|
|
|
MODEL_NAME: OBJECT_REPRESENTATION
|
|
|
|
|
|
If passed object has a callable get_absolute_url method, the
|
|
|
instance representation will be surrouned by an HTML anchor
|
|
|
(<a></a>) where target is set to value of the get_absolute_url()
|
|
|
method call.
|
|
|
|
|
|
Arguments:
|
|
|
obj - Model object whose representation should be returned.
|
|
|
|
|
|
Returns:
|
|
|
String represenation of passed model object.
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
return format_html('<strong>{0}</strong>: <a href="{1}">{2}</a>', capfirst(obj._meta.verbose_name), obj.get_absolute_url(), str(obj))
|
|
|
except AttributeError:
|
|
|
return format_html('<strong>{0}</strong>: {1}', capfirst(obj._meta.verbose_name), str(obj))
|
|
|
|
|
|
return collector.nested(formatter_callback)
|
|
|
|
|
|
|
|
|
class Project(RelatedCollectorMixin, 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:
|
|
@@ -59,12 +149,13 @@ class Project(models.Model):
|
|
|
description - Free-form description of the project.
|
|
|
"""
|
|
|
|
|
|
name = models.CharField(max_length=100, unique=True)
|
|
|
description = models.TextField(blank=True)
|
|
|
objects = SearchManager()
|
|
|
deletion_collect_models = ["Entity", "Interface"]
|
|
|
|
|
|
class Meta:
|
|
|
permissions = (("view", "Can view information"),)
|
|
|
|
|
|
def __unicode__(self):
|
|
|
"""
|
|
@@ -79,13 +170,13 @@ class Project(models.Model):
|
|
|
Return absolute URL for viewing a single project.
|
|
|
"""
|
|
|
|
|
|
return reverse("project", kwargs={'pk': self.pk})
|
|
|
|
|
|
|
|
|
class Location(models.Model):
|
|
|
class Location(RelatedCollectorMixin, 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.
|
|
|
|
|
|
Locations are not tied to specific project, and they do not have to be
|
|
@@ -115,13 +206,13 @@ class Location(models.Model):
|
|
|
String representation of a location.
|
|
|
"""
|
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
class Entity(models.Model):
|
|
|
class Entity(RelatedCollectorMixin, 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
|
|
|
the communication restrictions need to be applied across a subnet.
|
|
@@ -212,13 +303,13 @@ class Entity(models.Model):
|
|
|
# Make sure that entity has no communications in current project if
|
|
|
# moving it around.
|
|
|
if self.project != old_object.project and (self.incoming_communications() or self.outgoing_communications()):
|
|
|
raise ValidationError("The entity cannot be moved to different project as long as it has valid communications with entities in current project.")
|
|
|
|
|
|
|
|
|
class Interface(models.Model):
|
|
|
class Interface(RelatedCollectorMixin, 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.
|
|
|
|
|
@@ -258,13 +349,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):
|
|
|
class Communication(RelatedCollectorMixin, 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.
|
|
|
|