commit 727433eb0db41d3846146f75254b6ea321d25405 Author: Tor Martin SlÄen Date: Tue Mar 29 08:51:41 2011 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..3e4eedc --- /dev/null +++ b/manage.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +from django.core.management import execute_manager +import imp +try: + imp.find_module('settings') # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) + sys.exit(1) + +import settings + +if __name__ == "__main__": + execute_manager(settings) diff --git a/mdb/__init__.py b/mdb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mdb/admin.py b/mdb/admin.py new file mode 100644 index 0000000..ce117f1 --- /dev/null +++ b/mdb/admin.py @@ -0,0 +1,65 @@ +from mdb.models import * +from django.contrib import admin + +class InterfaceInline(admin.TabularInline): + model = Interface + extra = 0 + +class HostAdmin(admin.ModelAdmin): + inlines = [InterfaceInline] + list_display = ['hostname', 'brand', 'owner', 'host_type', 'location', 'serial_number', 'in_domain', 'created_date'] + readonly_fields = ['kerberos_principal_name', 'kerberos_principal_created_date', + 'kerberos_principal_created'] + fieldsets = ( + ('Owner Information', { + 'fields' : ( 'owner', 'location', 'description' ) + }), + ('Hardware Information', { + 'fields' : ( ('brand', 'model'), 'serial_number', 'host_type' ) + }), + ('Kerberos Information', { + 'description' : 'If this host is a member of the LDAP domain, you need to tick the request kerberos principal checkbox. A principal will then be created for the host.', +# 'classes' : [ 'collapse' ], + 'fields' : ( 'request_kerberos_principal', 'kerberos_principal_created', + ('kerberos_principal_name', 'kerberos_principal_created_date')) + }), +# ('Domain Information', { +# 'fields' : ('host_domains' ) +# }) + ) + +class Ip4AddressInline(admin.TabularInline): + model = Ip4Address + extra = 0 + readonly_fields = ['address'] + +class SubnetAdmin(admin.ModelAdmin): + list_display = ['name', 'network', 'netmask', 'num_addresses', 'broadcast_address', 'first_address', 'last_address'] + inlines = [Ip4AddressInline] + +class DomainSrvRecordInline(admin.TabularInline): + model = DomainSrvRecord + extra = 0 + +class DomainTxtRecordInline(admin.TabularInline): + model = DomainTxtRecord + extra = 0 + +class DomainCnameRecordInline(admin.TabularInline): + model = DomainCnameRecord + extra = 0 + +class DomainAdmin(admin.ModelAdmin): + inlines = [DomainSrvRecordInline, DomainTxtRecordInline, DomainCnameRecordInline] + list_display = ['domain_name', 'domain_soa', 'domain_admin', 'num_records', 'domain_ipaddr'] + + +class HostTypeAdmin(admin.ModelAdmin): + list_display = ['host_type', 'description', 'num_members'] + +admin.site.register(Domain, DomainAdmin) +admin.site.register(Host, HostAdmin) +admin.site.register(Ip4Subnet, SubnetAdmin) +admin.site.register(Nameserver) +admin.site.register(MailExchange) +admin.site.register(HostType, HostTypeAdmin) diff --git a/mdb/models.py b/mdb/models.py new file mode 100644 index 0000000..1b2f8bb --- /dev/null +++ b/mdb/models.py @@ -0,0 +1,193 @@ +from django.db import models +from django.db.models.signals import post_save +from django.db.models.signals import pre_delete +from django.dispatch import receiver + +import ipaddr + +# Create your models here. + +class Nameserver(models.Model): + hostname = models.CharField(max_length=256) + + def __unicode__(self): + return self.hostname + +class MailExchange(models.Model): + priority = models.IntegerField() + hostname = models.CharField(max_length=256) + + def __unicode__(self): + return "(" + str(self.priority) + ") " + self.hostname + +class Domain(models.Model): + domain_name = models.CharField(max_length=256) + domain_soa = models.CharField(max_length=256) + domain_ttl = models.IntegerField(default=60) + domain_serial = models.IntegerField(default=2011010101) + domain_refresh = models.IntegerField(default=28800) + domain_retry = models.IntegerField(default=7200) + domain_expire = models.IntegerField(default=604800) + domain_minimum_ttl = models.IntegerField(default=86400) + domain_admin = models.EmailField() + domain_ipaddr = models.IPAddressField() + + domain_nameservers = models.ManyToManyField(Nameserver) + domain_mailexchanges = models.ManyToManyField(MailExchange) + + def __unicode__(self): + return self.domain_name + + def num_records(self): + size = {} + size["srv"] = len(self.domainsrvrecord_set.all()) + size["txt"] = len(self.domaintxtrecord_set.all()) + size["a"] = len(self.host_set.all()) + return size + + num_records.short_description = "Num Records" + +class DomainSrvRecord(models.Model): + srvce = models.CharField(max_length=64) + prot = models.CharField(max_length=64) + name = models.CharField(max_length=128) + priority = models.IntegerField() + weight = models.IntegerField() + port = models.IntegerField() + target = models.CharField(max_length=256) + domain = models.ForeignKey(Domain) + + def __unicode__(self): + return self.srvce + "." + self.prot + "." + self.name + ". IN SRV " \ + + str(self.priority) + " " + str(self.weight) + " " + \ + str(self.port) + " " + self.target + "." + +class DomainTxtRecord(models.Model): + name = models.CharField(max_length=256) + target = models.CharField(max_length=256) + domain = models.ForeignKey(Domain) + + def __unicode__(self): + return self.name + " TXT " + self.target + +class DomainCnameRecord(models.Model): + name = models.CharField(max_length=256) + target = models.CharField(max_length=256) + domain = models.ForeignKey(Domain) + + def __unicode__(self): + return self.name + " IN CNAME " + self.target + +class Ip4Subnet(models.Model): + name = models.CharField(max_length=256) + netmask = models.IPAddressField() + network = models.IPAddressField() + + def __unicode__(self): + return self.network + " (" + self.name + ")" + + def num_addresses(self): + subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask) + return subnet.numhosts + + def broadcast_address(self): + subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask) + return subnet.broadcast + + def first_address(self): + subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask) + return subnet.iterhosts().next() + + def last_address(self): + subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask) + for curr in subnet.iterhosts(): + pass # horribly ineficcient + + return curr + + + broadcast_address.short_description = 'broadcast' + num_addresses.short_description = '#addresses' + first_address.short_description = 'first address' + last_address.short_description = 'last address' + + +class Ip4Address(models.Model): + subnet = models.ForeignKey(Ip4Subnet) + address = models.IPAddressField() + + def __unicode__(self): + return self.address + + def assigned_to_host(self): + self.interface_set.get().host + + assigned_to_host.short_description = "Assigned to Host" + +class HostType(models.Model): + host_type = models.CharField(max_length=64) + description = models.CharField(max_length=1024) + + def __unicode__(self): + return self.host_type + + def num_members(self): + return self.host_set.count() + +class Host(models.Model): + domain = models.ManyToManyField(Domain) + location = models.CharField(max_length=1024) + brand = models.CharField(max_length=1024) + model = models.CharField(max_length=1024) + owner = models.CharField(max_length=1024) + hostname = models.CharField(max_length=64) + serial_number = models.CharField(max_length=256) + description = models.CharField(max_length=1024) + created_date = models.DateTimeField(auto_now_add=True) + host_type = models.ForeignKey(HostType) + + request_kerberos_principal = models.BooleanField() + kerberos_principal_created = models.BooleanField() + kerberos_principal_name = models.CharField(max_length = 256) + kerberos_principal_created_date = models.DateTimeField() + + def __unicode__(self): + return self.hostname + + def in_domain(self): + domains = [] + for d in self.domain.all(): + domains.append(unicode(d)) + return ",".join(domains) + + in_domain.short_description = "in domains" + + + +class Interface(models.Model): + name = models.CharField(max_length=128) + macaddr = models.CharField(max_length=17) + pxe_filename = models.CharField(max_length=64, blank=True) + dhcp_client = models.BooleanField() + host = models.ForeignKey(Host) + ip4address = models.ForeignKey(Ip4Address, blank=True, null=True) + + def __unicode__(self): + return self.macaddr + +@receiver(post_save, sender=Ip4Subnet) +def create_ips_for_subnet(sender, instance, created, **kwargs): + if not created: + return + + subnet = ipaddr.IPv4Network(instance.network + "/" + instance.netmask) + + for addr in subnet.iterhosts(): + address = Ip4Address(address = str(addr), subnet=instance) + address.save() + +@receiver(pre_delete, sender=Ip4Subnet) +def delete_ips_for_subnet(sender, instance, **kwargs): + + for addr in instance.ip4address_set.all(): + addr.delete() diff --git a/mdb/tests.py b/mdb/tests.py new file mode 100644 index 0000000..501deb7 --- /dev/null +++ b/mdb/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/mdb/views.py b/mdb/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/mdb/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..1d4aca1 --- /dev/null +++ b/settings.py @@ -0,0 +1,146 @@ +# Django settings for dns_mdb project. + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + ('Tor Martin Slaaen', 'tormsl@sygard.no'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': 'dns_mdb', # Or path to database file if using sqlite3. + 'USER': 'dns_mdb', # Not used with sqlite3. + 'PASSWORD': 'dns_mdb', # Not used with sqlite3. + 'HOST': 'sql-server', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '3306', # Set to empty string for default. Not used with sqlite3. + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# On Unix systems, a value of None will cause Django to use the same +# timezone as the operating system. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'Europe/Oslo' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale +USE_L10N = True + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = '' + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/' + +# URL prefix for admin static files -- CSS, JavaScript and images. +# Make sure to use a trailing slash. +# Examples: "http://foo.com/static/admin/", "/static/admin/". +ADMIN_MEDIA_PREFIX = '/static/admin/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '@4ps=ebofcpv8sb#y7gm896=l&l*u0u-pgo7bcdj%+(k+2lqnl' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', +# 'django.template.loaders.eggs.Loader', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', +) + +ROOT_URLCONF = 'dns_mdb.urls' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'mdb', + # Uncomment the next line to enable the admin: + 'django.contrib.admin', + # Uncomment the next line to enable admin documentation: + # 'django.contrib.admindocs', +) + +# A sample logging configuration. The only tangible logging +# performed by this configuration is to send an email to +# the site admins on every HTTP 500 error. +# See http://docs.djangoproject.com/en/dev/topics/logging for +# more details on how to customize your logging configuration. +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': True, + }, + } +} diff --git a/urls.py b/urls.py new file mode 100644 index 0000000..58b1d10 --- /dev/null +++ b/urls.py @@ -0,0 +1,17 @@ +from django.conf.urls.defaults import patterns, include, url + +# Uncomment the next two lines to enable the admin: +from django.contrib import admin +admin.autodiscover() + +urlpatterns = patterns('', + # Examples: + # url(r'^$', 'dns_mdb.views.home', name='home'), + # url(r'^dns_mdb/', include('dns_mdb.foo.urls')), + + # Uncomment the admin/doc line below to enable admin documentation: + # url(r'^admin/doc/', include('django.contrib.admindocs.urls')), + + # Uncomment the next line to enable the admin: + (r'^admin/', include(admin.site.urls)), +)