Bump everything (python3 ftw), starts verify api
This commit is contained in:
1 parent
bc6029e289
commit
9ff22d634f
17 files changed
+336
-287
No files matched your search
+2
-2
@@ -2,7 +2,7 @@
|
||||
*.swp
|
||||
temp
|
||||
*.log
|
||||
settings.py
|
||||
dns_mdb.db
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
/.idea
|
||||
/venv
|
||||
@@ -1,17 +0,0 @@
|
||||
A Django app for managing computer equipment.
|
||||
Generates DHCP configs and zone files.
|
||||
|
||||
Dependencies:
|
||||
sudo apt-get install libmysqlclient-dev python-dev libldap2-dev libsasl2-dev bind9utils
|
||||
|
||||
Setup environment:
|
||||
mdb$ virtualenv venv
|
||||
mdb$ . venv/bin/activate
|
||||
(venv)mdb$ pip install -r requirements.txt
|
||||
|
||||
Create a config file:
|
||||
mdb$ cp mdb/settings-sample.py mdb/settings.py
|
||||
# Edit settings.py with your favorite editor
|
||||
|
||||
Run the server:
|
||||
(venv)mdb$ python manage.py runserver
|
||||
@@ -0,0 +1,15 @@
|
||||
A Django app for managing computer equipment.
|
||||
|
||||
## Installation
|
||||
sudo apt-get install libmysqlclient-dev python-dev libldap2-dev libsasl2-dev bind9utils
|
||||
virtualenv venv
|
||||
. venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
python manage.py migrate
|
||||
python manage.py runserver
|
||||
|
||||
## Features
|
||||
|
||||
* Creates DHCPD configuration files
|
||||
* Creates DNS zone files for BIND
|
||||
* TODO: Creates PXE config files (with random secret for use with Puppet autosign)
|
||||
@@ -1,9 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
import os, sys
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mdb.settings")
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mdbsite.settings")
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
execute_from_command_line(sys.argv)
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,6 @@
|
||||
from rest_framework.views import APIView
|
||||
|
||||
|
||||
class ValidatePuppetHostSecret(APIView):
|
||||
# TODO
|
||||
pass
|
||||
@@ -6,7 +6,11 @@ from difflib import context_diff
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.mail import mail_admins
|
||||
from optparse import make_option
|
||||
from commands import getstatusoutput
|
||||
try:
|
||||
from subprocess import getstatusoutput
|
||||
except ImportError:
|
||||
from commands import getstatusoutput
|
||||
|
||||
from mdb.models import DhcpConfig
|
||||
|
||||
|
||||
@@ -42,13 +46,13 @@ class Command(BaseCommand):
|
||||
|
||||
# do we need to do anything?
|
||||
if config.serial == config.active_serial and not force:
|
||||
print "Nothing to do, serial is the same: %s" % config.serial
|
||||
print("Nothing to do, serial is the same: %s" % config.serial)
|
||||
sys.exit(0)
|
||||
|
||||
# write to stdout
|
||||
if output == sys.stdout:
|
||||
print config.dhcpd_configuration()
|
||||
print 'Not writing to file, serial not updated'
|
||||
print(config.dhcpd_configuration())
|
||||
print('Not writing to file, serial not updated')
|
||||
return
|
||||
|
||||
# read current file contents
|
||||
@@ -71,7 +75,7 @@ class Command(BaseCommand):
|
||||
tofile=config.serial,
|
||||
lineterm=''))
|
||||
|
||||
print diff
|
||||
print(diff)
|
||||
|
||||
# update serial
|
||||
old_serial = config.active_serial
|
||||
|
||||
@@ -7,8 +7,12 @@ from difflib import context_diff
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.mail import mail_admins
|
||||
from optparse import make_option
|
||||
from commands import getstatusoutput
|
||||
from mdb.models import *
|
||||
try:
|
||||
from subprocess import getstatusoutput
|
||||
except ImportError:
|
||||
from commands import getstatusoutput
|
||||
|
||||
from mdb.models import Domain, Ip4Subnet, Ip6Subnet
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
@@ -43,7 +47,7 @@ class Command(BaseCommand):
|
||||
# do the binaries exist?
|
||||
for f in (self.checkzone_bin, self.bind_bin):
|
||||
if not os.path.isfile(f):
|
||||
print "ERROR: no such file %s, exiting..." % f
|
||||
print("ERROR: no such file %s, exiting..." % f)
|
||||
if not debug:
|
||||
sys.exit(1)
|
||||
|
||||
@@ -106,11 +110,11 @@ class Command(BaseCommand):
|
||||
'diff': None,
|
||||
}
|
||||
|
||||
print "updating %s %s [%d -> %d]" % (
|
||||
print("updating %s %s [%d -> %d]" % (
|
||||
zonetype,
|
||||
zone.domain_name,
|
||||
zone.domain_active_serial,
|
||||
zone.domain_serial)
|
||||
zone.domain_serial))
|
||||
|
||||
# generate zone file contents
|
||||
new = zone.zone_file_contents()
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.core.validators
|
||||
import re
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mdb', '0005_auto_20150822_2204'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='dhcpcustomfield',
|
||||
options={'verbose_name': 'DHCP custom field'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='domain',
|
||||
name='domain_admin',
|
||||
field=models.EmailField(max_length=254),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='domain',
|
||||
name='domain_ipaddr',
|
||||
field=models.GenericIPAddressField(protocol='IPv4'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='host',
|
||||
name='hostname',
|
||||
field=models.CharField(validators=[django.core.validators.RegexValidator(code='invalid', message='Enter a valid hostname', regex=re.compile('^(?!-)[-a-z0-9]+(?<!-)$', 34))], max_length=64),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='ip4address',
|
||||
field=models.OneToOneField(to='mdb.Ip4Address', null=True, blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='macaddr',
|
||||
field=models.CharField(validators=[django.core.validators.RegexValidator(code='invalid', message='Enter a valid MAC address', regex=re.compile('^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$', 34))], max_length=17),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip4address',
|
||||
name='address',
|
||||
field=models.GenericIPAddressField(protocol='IPv4'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip4subnet',
|
||||
name='dhcp_dynamic_end',
|
||||
field=models.GenericIPAddressField(protocol='IPv4', null=True, blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip4subnet',
|
||||
name='dhcp_dynamic_start',
|
||||
field=models.GenericIPAddressField(protocol='IPv4', null=True, blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip4subnet',
|
||||
name='domain_admin',
|
||||
field=models.EmailField(max_length=254),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip4subnet',
|
||||
name='netmask',
|
||||
field=models.GenericIPAddressField(protocol='IPv4'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip4subnet',
|
||||
name='network',
|
||||
field=models.GenericIPAddressField(protocol='IPv4'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='ip6subnet',
|
||||
name='domain_admin',
|
||||
field=models.EmailField(max_length=254),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operatingsystem',
|
||||
name='arch',
|
||||
field=models.CharField(max_length=255, choices=[('mips', 'MIPS'), ('arm', 'ARM'), ('broadcom', 'Broadcom'), ('rc32300', 'RC32300'), ('powerpc', 'PowerPC'), ('powerpc403ga', 'PowerPC403GA'), ('unknown', 'Unknown'), ('x86_64', 'x86-64'), ('i386', 'x86')], null=True, blank=True),
|
||||
),
|
||||
]
|
||||
+59
-41
@@ -2,31 +2,36 @@ from django.db import models
|
||||
from django.db.models import Count
|
||||
from django.db.models.signals import post_save, pre_save, pre_delete
|
||||
from django.dispatch import receiver
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.six import u
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
from validators import validate_hostname, validate_macaddr
|
||||
from mdb.validators import validate_hostname, validate_macaddr
|
||||
|
||||
import ipaddr
|
||||
import ipaddress
|
||||
import datetime
|
||||
import re
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Nameserver(models.Model):
|
||||
hostname = models.CharField(max_length=256)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.hostname
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class MailExchange(models.Model):
|
||||
priority = models.IntegerField()
|
||||
hostname = models.CharField(max_length=256)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return "(" + str(self.priority) + ") " + self.hostname
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Domain(models.Model):
|
||||
domain_name = models.CharField(max_length=256)
|
||||
domain_soa = models.CharField(max_length=256)
|
||||
@@ -38,14 +43,14 @@ class Domain(models.Model):
|
||||
domain_expire = models.IntegerField(default=604800)
|
||||
domain_minimum_ttl = models.IntegerField(default=86400)
|
||||
domain_admin = models.EmailField()
|
||||
domain_ipaddr = models.IPAddressField()
|
||||
domain_ipaddr = models.GenericIPAddressField(protocol='IPv4')
|
||||
domain_filename = models.CharField(max_length=256)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
domain_nameservers = models.ManyToManyField(Nameserver)
|
||||
domain_mailexchanges = models.ManyToManyField(MailExchange)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.domain_name
|
||||
|
||||
def num_records(self):
|
||||
@@ -63,6 +68,7 @@ class Domain(models.Model):
|
||||
def __eq__(self, other):
|
||||
if not other or not hasattr(other, 'domain_name'):
|
||||
return False
|
||||
|
||||
return self.domain_name == other.domain_name
|
||||
|
||||
def zone_file_contents(self):
|
||||
@@ -93,12 +99,12 @@ class Domain(models.Model):
|
||||
content += "; SRV records\n"
|
||||
|
||||
for srv in self.domainsrvrecord_set.all():
|
||||
content += unicode(srv) + "\n"
|
||||
content += u(srv) + "\n"
|
||||
|
||||
content += "; A records\n"
|
||||
|
||||
for a in self.domainarecord_set.all():
|
||||
content += unicode(a) + "\n"
|
||||
content += u(a) + "\n"
|
||||
|
||||
content += "; CNAME records \n"
|
||||
|
||||
@@ -108,7 +114,7 @@ class Domain(models.Model):
|
||||
content += "; TXT records \n"
|
||||
|
||||
for txt in self.domaintxtrecord_set.all():
|
||||
content += unicode(txt) + "\n"
|
||||
content += u(txt) + "\n"
|
||||
|
||||
content += "; HOST records\n"
|
||||
|
||||
@@ -126,6 +132,7 @@ class Domain(models.Model):
|
||||
return content
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DomainSrvRecord(models.Model):
|
||||
srvce = models.CharField(max_length=64)
|
||||
prot = models.CharField(max_length=64)
|
||||
@@ -137,42 +144,46 @@ class DomainSrvRecord(models.Model):
|
||||
domain = models.ForeignKey(Domain)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.srvce + "." + self.prot + "." + self.name + ". IN SRV " \
|
||||
+ str(self.priority) + " " + str(self.weight) + " " + \
|
||||
str(self.port) + " " + self.target + "."
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DomainTxtRecord(models.Model):
|
||||
name = models.CharField(max_length=256)
|
||||
target = models.CharField(max_length=256)
|
||||
domain = models.ForeignKey(Domain)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name + " TXT " + self.target
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DomainCnameRecord(models.Model):
|
||||
name = models.CharField(max_length=256)
|
||||
target = models.CharField(max_length=256)
|
||||
domain = models.ForeignKey(Domain)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name + " IN CNAME " + self.target
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DomainARecord(models.Model):
|
||||
name = models.CharField(max_length=256)
|
||||
target = models.CharField(max_length=256)
|
||||
domain = models.ForeignKey(Domain)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name + " IN A " + self.target
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DhcpConfig(models.Model):
|
||||
serial = models.IntegerField()
|
||||
active_serial = models.IntegerField()
|
||||
@@ -229,13 +240,14 @@ class DhcpConfig(models.Model):
|
||||
|
||||
return content
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'DHCP config'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Ip6Subnet(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
network = models.CharField(max_length=255)
|
||||
@@ -254,7 +266,7 @@ class Ip6Subnet(models.Model):
|
||||
domain_admin = models.EmailField()
|
||||
domain_filename = models.CharField(max_length=256)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.network + " (" + self.name + ")"
|
||||
|
||||
def zone_file_contents(self, generate_unassigned=False):
|
||||
@@ -292,7 +304,7 @@ class Ip6Subnet(models.Model):
|
||||
addr.interface.host.hostname,
|
||||
addr.interface.domain.domain_name)
|
||||
|
||||
ip = ipaddr.IPv6Address(self.network + addr.address)
|
||||
ip = ipaddress.IPv6Address(self.network + addr.address)
|
||||
ip = ".".join(ip.exploded.replace(":", "")[16:])[::-1]
|
||||
content += "%s\tPTR\t%s.\n" % (ip, hostname)
|
||||
|
||||
@@ -305,10 +317,11 @@ class Ip6Subnet(models.Model):
|
||||
verbose_name = 'IPv6 subnet'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Ip4Subnet(models.Model):
|
||||
name = models.CharField(max_length=256)
|
||||
netmask = models.IPAddressField()
|
||||
network = models.IPAddressField()
|
||||
netmask = models.GenericIPAddressField(protocol='IPv4')
|
||||
network = models.GenericIPAddressField(protocol='IPv4')
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
domain_name = models.CharField(max_length=255, editable=False)
|
||||
domain_nameservers = models.ManyToManyField(Nameserver)
|
||||
@@ -324,29 +337,29 @@ class Ip4Subnet(models.Model):
|
||||
domain_filename = models.CharField(max_length=256)
|
||||
|
||||
dhcp_dynamic = models.BooleanField(default=False)
|
||||
dhcp_dynamic_start = models.IPAddressField(null=True, blank=True)
|
||||
dhcp_dynamic_end = models.IPAddressField(null=True, blank=True)
|
||||
dhcp_dynamic_start = models.GenericIPAddressField(protocol='IPv4', null=True, blank=True)
|
||||
dhcp_dynamic_end = models.GenericIPAddressField(protocol='IPv4', null=True, blank=True)
|
||||
dhcp_config = models.ForeignKey(DhcpConfig)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.network + " (" + self.name + ")"
|
||||
|
||||
def num_addresses(self):
|
||||
subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask)
|
||||
subnet = ipaddress.IPv4Network(self.network + "/" + self.netmask)
|
||||
return subnet.numhosts
|
||||
|
||||
def broadcast_address(self):
|
||||
subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask)
|
||||
subnet = ipaddress.IPv4Network(self.network + "/" + self.netmask)
|
||||
return subnet.broadcast
|
||||
|
||||
def first_address(self):
|
||||
subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask)
|
||||
subnet = ipaddress.IPv4Network(self.network + "/" + self.netmask)
|
||||
return subnet.iterhosts().next()
|
||||
|
||||
def last_address(self):
|
||||
subnet = ipaddr.IPv4Network(self.network + "/" + self.netmask)
|
||||
subnet = ipaddress.IPv4Network(self.network + "/" + self.netmask)
|
||||
for curr in subnet.iterhosts():
|
||||
pass # horribly ineficcient
|
||||
pass # horribly inefficient
|
||||
|
||||
return curr
|
||||
|
||||
@@ -405,18 +418,20 @@ class Ip4Subnet(models.Model):
|
||||
verbose_name = 'IPv4 subnet'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DhcpOption(models.Model):
|
||||
key = models.CharField(max_length=255)
|
||||
value = models.CharField(max_length=255)
|
||||
ip4subnet = models.ForeignKey(Ip4Subnet)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.key + " " + self.value
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'DHCP option'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DhcpCustomField(models.Model):
|
||||
value = models.CharField(max_length=255)
|
||||
ip4subnet = models.ForeignKey(Ip4Subnet)
|
||||
@@ -425,22 +440,20 @@ class DhcpCustomField(models.Model):
|
||||
verbose_name = 'DHCP custom field'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Ip4Address(models.Model):
|
||||
subnet = models.ForeignKey(Ip4Subnet)
|
||||
address = models.IPAddressField()
|
||||
address = models.GenericIPAddressField(protocol='IPv4')
|
||||
last_contact = models.DateTimeField(null=True, blank=True)
|
||||
ping_avg_rtt = models.FloatField(null=True, blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
# FIXME: generates 2 SQL queries
|
||||
_if = self.interface_set.all()
|
||||
if not _if:
|
||||
return self.address
|
||||
|
||||
return "{} ({})".format(
|
||||
self.address,
|
||||
_if.get().host.hostname
|
||||
)
|
||||
return "{} ({})".format(self.address, _if.get().host.hostname)
|
||||
|
||||
def assigned_to_host(self):
|
||||
return self.interface_set.get().host
|
||||
@@ -452,11 +465,12 @@ class Ip4Address(models.Model):
|
||||
verbose_name_plural = 'IPv4 addresses'
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class HostType(models.Model):
|
||||
host_type = models.CharField(max_length=64)
|
||||
description = models.CharField(max_length=1024)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.host_type
|
||||
|
||||
def num_members(self):
|
||||
@@ -466,6 +480,7 @@ class HostType(models.Model):
|
||||
ordering = ("host_type",)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class OperatingSystem(models.Model):
|
||||
OS_ARCHITECTURES = (
|
||||
('mips', _('MIPS')),
|
||||
@@ -482,13 +497,14 @@ class OperatingSystem(models.Model):
|
||||
version = models.CharField(max_length=64)
|
||||
arch = models.CharField(max_length=255, choices=OS_ARCHITECTURES, blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name + " " + self.version + " (" + self.arch + ")"
|
||||
|
||||
class Meta:
|
||||
ordering = ("name", "version")
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Host(models.Model):
|
||||
location = models.CharField(max_length=1024)
|
||||
brand = models.CharField(max_length=1024)
|
||||
@@ -507,7 +523,7 @@ class Host(models.Model):
|
||||
kerberos_principal_name = models.CharField(max_length=256, editable=False)
|
||||
kerberos_principal_created_date = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.hostname
|
||||
|
||||
def in_domain(self):
|
||||
@@ -531,23 +547,25 @@ class Host(models.Model):
|
||||
return ",".join(addresses)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Interface(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
macaddr = models.CharField(max_length=17, validators=[validate_macaddr])
|
||||
pxe_filename = models.CharField(max_length=64, blank=True)
|
||||
dhcp_client = models.BooleanField(default=False)
|
||||
host = models.ForeignKey(Host)
|
||||
ip4address = models.ForeignKey(Ip4Address, blank=True, null=True, unique=True)
|
||||
ip4address = models.OneToOneField(Ip4Address, blank=True, null=True)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
domain = models.ForeignKey(Domain)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return "%s (%s on %s)" % (self.macaddr, self.name, self.host.hostname)
|
||||
|
||||
def ipv6_enabled(self):
|
||||
return self.ip6address_set.count() > 0
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Ip6Address(models.Model):
|
||||
subnet = models.ForeignKey(Ip6Subnet)
|
||||
address = models.CharField(max_length=64)
|
||||
@@ -556,7 +574,7 @@ class Ip6Address(models.Model):
|
||||
def full_address(self):
|
||||
return self.subnet.network + self.address
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return "%s (%s on %s)" % (
|
||||
self.full_address(),
|
||||
self.interface.name,
|
||||
@@ -604,7 +622,7 @@ def create_ips_for_subnet(sender, instance, created, **kwargs):
|
||||
if not created:
|
||||
return
|
||||
|
||||
subnet = ipaddr.IPv4Network(instance.network + "/" + instance.netmask)
|
||||
subnet = ipaddress.IPv4Network(instance.network + "/" + instance.netmask)
|
||||
|
||||
for addr in subnet.iterhosts():
|
||||
address = Ip4Address(address=str(addr), subnet=instance)
|
||||
@@ -642,7 +660,7 @@ def set_domain_name_for_ipv6_subnet(sender, instance, **kwargs):
|
||||
if len(instance.domain_name) > 0:
|
||||
return
|
||||
|
||||
network = ipaddr.IPv6Address("%s::" % instance.network)
|
||||
network = ipaddress.IPv6Address("%s::" % instance.network)
|
||||
instance.domain_name = ".".join(network.exploded.replace(":", "")[:16])[::-1] + ".ip6.arpa"
|
||||
|
||||
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
# Django settings for dns_mdb project.
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('System Administrator', 'sysadmin@example.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||
'NAME': 'mdb.db', # Or path to database file if using sqlite3.
|
||||
'USER': 'mdb', # Not used with sqlite3.
|
||||
'PASSWORD': 'mdb', # Not used with sqlite3.
|
||||
'HOST': '', # 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 = '/media/'
|
||||
|
||||
# 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 = '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',
|
||||
'suit',
|
||||
'django.contrib.admin',
|
||||
)
|
||||
|
||||
# Defines a test runner
|
||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
|
||||
|
||||
# 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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
EMAIL_SUBJECT_PREFIX = '[MDB] '
|
||||
EMAIL_HOST = 'smtp.example.com'
|
||||
EMAIL_PORT = 25
|
||||
|
||||
|
||||
# for django-suit
|
||||
from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = TCP + (
|
||||
'django.core.context_processors.request',
|
||||
)
|
||||
|
||||
# django-suit configuration
|
||||
SUIT_CONFIG = {
|
||||
# header
|
||||
'ADMIN_NAME': 'MDB',
|
||||
'HEADER_DATE_FORMAT': 'l, Y-m-d',
|
||||
'HEADER_TIME_FORMAT': 'H:i',
|
||||
|
||||
# forms
|
||||
# 'SHOW_REQUIRED_ASTERISK': True, # Default True
|
||||
# 'CONFIRM_UNSAVED_CHANGES': True, # Default True
|
||||
|
||||
# menu
|
||||
'SEARCH_URL': '/admin/mdb/host/',
|
||||
# 'MENU_ICONS': {
|
||||
# 'sites': 'icon-leaf',
|
||||
# 'auth': 'icon-lock',
|
||||
# },
|
||||
# 'MENU_OPEN_FIRST_CHILD': True, # Default True
|
||||
# 'MENU_EXCLUDE': ('auth.group',),
|
||||
'MENU': (
|
||||
{'app': 'mdb', 'label': 'MDB', 'url': 'mdb.host'},
|
||||
{
|
||||
'label': 'Settings',
|
||||
'icon': 'icon-cog',
|
||||
'models': ('auth.user', 'auth.group')
|
||||
},
|
||||
),
|
||||
|
||||
# misc
|
||||
'LIST_PER_PAGE': 30
|
||||
}
|
||||
+10
-14
@@ -1,16 +1,12 @@
|
||||
"""
|
||||
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
|
||||
from django.core.urlresolvers import reverse
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.assertEqual(1 + 1, 2)
|
||||
class APITestCases(APITestCase):
|
||||
def test_validate_puppet_host_by_secret(self):
|
||||
data = {
|
||||
'secret': 'something',
|
||||
'certname': 'arnold.neuf.no'
|
||||
}
|
||||
res = self.client.post(reverse('api-validate-host-secret'), data)
|
||||
self.fail()
|
||||
@@ -0,0 +1,128 @@
|
||||
import os
|
||||
from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
ADMINS = (
|
||||
('System Administrator', 'sysadmin@example.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
TIME_ZONE = 'Europe/Oslo'
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
MEDIA_URL = '/media/'
|
||||
ADMIN_MEDIA_PREFIX = '/media/'
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
|
||||
# Additional locations of static files
|
||||
STATICFILES_DIRS = (
|
||||
)
|
||||
|
||||
# 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'
|
||||
|
||||
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 = 'mdbsite.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',
|
||||
'suit',
|
||||
'django.contrib.admin',
|
||||
)
|
||||
|
||||
# Defines a test runner
|
||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
|
||||
|
||||
EMAIL_SUBJECT_PREFIX = '[MDB] '
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = TCP + (
|
||||
'django.core.context_processors.request', # for django-suit
|
||||
)
|
||||
|
||||
# django-suit configuration
|
||||
SUIT_CONFIG = {
|
||||
# header
|
||||
'ADMIN_NAME': 'MDB',
|
||||
'HEADER_DATE_FORMAT': 'l, Y-m-d',
|
||||
'HEADER_TIME_FORMAT': 'H:i',
|
||||
|
||||
# forms
|
||||
# 'SHOW_REQUIRED_ASTERISK': True, # Default True
|
||||
# 'CONFIRM_UNSAVED_CHANGES': True, # Default True
|
||||
|
||||
# menu
|
||||
'SEARCH_URL': '/admin/mdb/host/',
|
||||
# 'MENU_ICONS': {
|
||||
# 'sites': 'icon-leaf',
|
||||
# 'auth': 'icon-lock',
|
||||
# },
|
||||
# 'MENU_OPEN_FIRST_CHILD': True, # Default True
|
||||
# 'MENU_EXCLUDE': ('auth.group',),
|
||||
'MENU': (
|
||||
{'app': 'mdb', 'label': 'MDB', 'url': 'mdb.host'},
|
||||
{
|
||||
'label': 'Settings',
|
||||
'icon': 'icon-cog',
|
||||
'models': ('auth.user', 'auth.group')
|
||||
},
|
||||
),
|
||||
|
||||
# misc
|
||||
'LIST_PER_PAGE': 30
|
||||
}
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
|
||||
'PAGINATE_BY': 10
|
||||
}
|
||||
|
||||
try:
|
||||
from local_settings import *
|
||||
except ImportError:
|
||||
pass
|
||||
@@ -1,14 +1,15 @@
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.views.generic.base import RedirectView
|
||||
from mdb.api.views import ValidatePuppetHostSecret
|
||||
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
urlpatterns = [
|
||||
url(r'^$', RedirectView.as_view(url='admin/')),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
)
|
||||
url(r'^api/validate-host-secret', ValidatePuppetHostSecret.as_view(), name='api-validate-host-secret')
|
||||
]
|
||||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
File renamed without changes.
+5
-4
@@ -1,5 +1,6 @@
|
||||
Django>=1.7,<1.8
|
||||
MySQL-python==1.2.5
|
||||
ipaddr==2.1.11
|
||||
Django>=1.8,<1.9
|
||||
django-auth-ldap
|
||||
django-suit
|
||||
django-suit==0.2.15
|
||||
djangorestframework==3.2.4
|
||||
ipaddress==1.0.14
|
||||
mysqlclient==1.3.6
|
||||
Reference in new issue
Block a user