summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Hostbase
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/Server/Hostbase')
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/.gitignore3
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/__init__.py0
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/backends.py68
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py0
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/admin.py15
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/models.py210
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/sql/zone.sql2
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/urls.py68
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/views.py970
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/base.html34
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/confirm.html117
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/copy.html122
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dns.html40
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dnsedit.html98
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/edit.html191
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/errors.html31
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/host.html80
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/host_confirm_delete.html89
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/log_detail.html23
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/index.html16
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/login.html37
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.html13
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.tmpl6
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logviewer.html27
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/navbar.tmpl5
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/new.html102
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/remove.html89
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/results.html45
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/search.html57
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneedit.html81
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zonenew.html43
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zones.html37
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneview.html71
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/ldapauth.py180
-rwxr-xr-xsrc/lib/Bcfg2/Server/Hostbase/manage.py11
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/media/base.css5
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/media/boxypastel.css179
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/media/global.css8
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/media/layout.css62
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/nisauth.py40
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/regex.py6
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/settings.py143
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/batchadd.tmpl29
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.conf.head5
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.tmpl17
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/hosts.tmpl26
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/hostsappend.tmpl5
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/named.tmpl69
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/namedviews.tmpl92
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/reverseappend.tmpl4
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/reversesoa.tmpl13
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/templates/zone.tmpl18
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/test/harness.py11
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/test/test_environ_settings.py35
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/test/test_ldapauth.py10
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/test/test_settings.py12
-rw-r--r--src/lib/Bcfg2/Server/Hostbase/urls.py27
57 files changed, 3797 insertions, 0 deletions
diff --git a/src/lib/Bcfg2/Server/Hostbase/.gitignore b/src/lib/Bcfg2/Server/Hostbase/.gitignore
new file mode 100644
index 000000000..8e15b5395
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/.gitignore
@@ -0,0 +1,3 @@
+*.pyc
+dev.db
+bcfg2.conf
diff --git a/src/lib/Bcfg2/Server/Hostbase/__init__.py b/src/lib/Bcfg2/Server/Hostbase/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/__init__.py
diff --git a/src/lib/Bcfg2/Server/Hostbase/backends.py b/src/lib/Bcfg2/Server/Hostbase/backends.py
new file mode 100644
index 000000000..ecaf3c109
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/backends.py
@@ -0,0 +1,68 @@
+from django.contrib.auth.models import User
+#from ldapauth import *
+from nisauth import *
+
+## class LDAPBackend(object):
+
+## def authenticate(self,username=None,password=None):
+## try:
+
+## l = ldapauth(username,password)
+## temp_pass = User.objects.make_random_password(100)
+## ldap_user = dict(username=l.sAMAccountName,
+## )
+## user_session_obj = dict(
+## email=l.email,
+## first_name=l.name_f,
+## last_name=l.name_l,
+## uid=l.badge_no
+## )
+## #fixme: need to add this user session obj to session
+## #print str(ldap_user)
+## user,created = User.objects.get_or_create(username=username)
+## #print user
+## #print "created " + str(created)
+## return user
+
+## except LDAPAUTHError,e:
+## #print str(e)
+## return None
+
+## def get_user(self,user_id):
+## try:
+## return User.objects.get(pk=user_id)
+## except User.DoesNotExist, e:
+## print str(e)
+## return None
+
+
+class NISBackend(object):
+
+ def authenticate(self, username=None, password=None):
+ try:
+ n = nisauth(username, password)
+ temp_pass = User.objects.make_random_password(100)
+ nis_user = dict(username=username,
+ )
+
+ user_session_obj = dict(
+ email = username + "@mcs.anl.gov",
+ first_name = None,
+ last_name = None,
+ uid = n.uid
+ )
+ user, created = User.objects.get_or_create(username=username)
+
+ return user
+
+ except NISAUTHError:
+ e = sys.exc_info()[1]
+ return None
+
+
+ def get_user(self, user_id):
+ try:
+ return User.objects.get(pk=user_id)
+ except User.DoesNotExist:
+ e = sys.exc_info()[1]
+ return None
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py b/src/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/__init__.py
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/admin.py b/src/lib/Bcfg2/Server/Hostbase/hostbase/admin.py
new file mode 100644
index 000000000..70a2233cc
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/admin.py
@@ -0,0 +1,15 @@
+from django.contrib import admin
+
+from models import Host, Interface, IP, MX, Name, CName, Nameserver, ZoneAddress, Zone, Log, ZoneLog
+
+admin.site.register(Host)
+admin.site.register(Interface)
+admin.site.register(IP)
+admin.site.register(MX)
+admin.site.register(Name)
+admin.site.register(CName)
+admin.site.register(Nameserver)
+admin.site.register(ZoneAddress)
+admin.site.register(Zone)
+admin.site.register(Log)
+admin.site.register(ZoneLog)
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/models.py b/src/lib/Bcfg2/Server/Hostbase/hostbase/models.py
new file mode 100644
index 000000000..3f08a09a0
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/models.py
@@ -0,0 +1,210 @@
+from django.db import models
+
+# Create your models here.
+class Host(models.Model):
+ NETGROUP_CHOICES = (
+ ('none', 'none'),('cave', 'cave'),('ccst', 'ccst'),('mcs', 'mcs'),
+ ('mmlab', 'mmlab'),('sp', 'sp'),('red', 'red'),('virtual', 'virtual'),
+ ('win', 'win'),('xterm', 'xterm'),('lcrc', 'lcrc'),('anlext', 'anlext'),
+ ('teragrid', 'teragrid')
+ )
+ STATUS_CHOICES = (
+ ('active','active'),('dormant','dormant')
+ )
+ SUPPORT_CHOICES = (
+ ('green','green'),('yellow','yellow'),('red','red')
+ )
+ CLASS_CHOICES = (
+ ('scientific','scientific'),
+ ('operations','operations'),('guest','guest'),
+ ('confidential','confidential'),('public','public')
+ )
+ WHATAMI_CHOICES = (
+ ('aix-3', 'aix-3'), ('aix-4', 'aix-4'),
+ ('aix-5', 'aix-5'), ('baytech', 'baytech'),
+ ('decserver', 'decserver'), ('dialup', 'dialup'),
+ ('dos', 'dos'), ('freebsd', 'freebsd'),
+ ('hpux', 'hpux'), ('irix-5', 'irix-5'),
+ ('irix-6', 'irix-6'), ('linux', 'linux'),
+ ('linux-2', 'linux-2'), ('linux-rh73', 'linux-rh73'),
+ ('linux-rh8', 'linux-rh8'), ('linux-sles8', 'linux-sles8'),
+ ('linux-sles8-64', 'linux-sles8-64'), ('linux-sles8-ia32', 'linux-sles8-ia32'),
+ ('linux-sles8-ia64', 'linux-sles8-ia64'), ('mac', 'mac'),
+ ('network', 'network'), ('next', 'next'),
+ ('none', 'none'), ('osf', 'osf'), ('printer', 'printer'),
+ ('robot', 'robot'), ('solaris-2', 'solaris-2'),
+ ('sun4', 'sun4'), ('unknown', 'unknown'), ('virtual', 'virtual'),
+ ('win31', 'win31'), ('win95', 'win95'),
+ ('winNTs', 'winNTs'), ('winNTw', 'winNTw'),
+ ('win2k', 'win2k'), ('winXP', 'winXP'), ('xterm', 'xterm')
+ )
+ hostname = models.CharField(max_length=64)
+ whatami = models.CharField(max_length=16)
+ netgroup = models.CharField(max_length=32, choices=NETGROUP_CHOICES)
+ security_class = models.CharField('class', max_length=16)
+ support = models.CharField(max_length=8, choices=SUPPORT_CHOICES)
+ csi = models.CharField(max_length=32, blank=True)
+ printq = models.CharField(max_length=32, blank=True)
+ outbound_smtp = models.BooleanField()
+ primary_user = models.EmailField()
+ administrator = models.EmailField(blank=True)
+ location = models.CharField(max_length=16)
+ comments = models.TextField(blank=True)
+ expiration_date = models.DateField(null=True, blank=True)
+ last = models.DateField(auto_now=True, auto_now_add=True)
+ status = models.CharField(max_length=7, choices=STATUS_CHOICES)
+ dirty = models.BooleanField()
+
+ class Admin:
+ list_display = ('hostname', 'last')
+ search_fields = ['hostname']
+
+ def __str__(self):
+ return self.hostname
+
+ def get_logs(self):
+ """
+ Get host's log.
+ """
+ return Log.objects.filter(hostname=self.hostname)
+
+class Interface(models.Model):
+ TYPE_CHOICES = (
+ ('eth', 'ethernet'), ('wl', 'wireless'), ('virtual', 'virtual'), ('myr', 'myr'),
+ ('mgmt', 'mgmt'), ('tape', 'tape'), ('fe', 'fe'), ('ge', 'ge'),
+ )
+ # FIXME: The new admin interface has change a lot.
+ #host = models.ForeignKey(Host, edit_inline=models.TABULAR, num_in_admin=2)
+ host = models.ForeignKey(Host)
+ # FIXME: The new admin interface has change a lot.
+ #mac_addr = models.CharField(max_length=32, core=True)
+ mac_addr = models.CharField(max_length=32)
+ hdwr_type = models.CharField('type', max_length=16, choices=TYPE_CHOICES, blank=True)
+ # FIXME: The new admin interface has change a lot.
+ # radio_admin=True, blank=True)
+ dhcp = models.BooleanField()
+
+ def __str__(self):
+ return self.mac_addr
+
+ class Admin:
+ list_display = ('mac_addr', 'host')
+ search_fields = ['mac_addr']
+
+class IP(models.Model):
+ interface = models.ForeignKey(Interface)
+ # FIXME: The new admin interface has change a lot.
+ # edit_inline=models.TABULAR, num_in_admin=1)
+ #ip_addr = models.IPAddressField(core=True)
+ ip_addr = models.IPAddressField()
+
+ def __str__(self):
+ return self.ip_addr
+
+ class Admin:
+ pass
+
+ class Meta:
+ ordering = ('ip_addr', )
+
+class MX(models.Model):
+ priority = models.IntegerField(blank=True)
+ # FIXME: The new admin interface has change a lot.
+ #mx = models.CharField(max_length=64, blank=True, core=True)
+ mx = models.CharField(max_length=64, blank=True)
+
+ def __str__(self):
+ return (" ".join([str(self.priority), self.mx]))
+
+ class Admin:
+ pass
+
+class Name(models.Model):
+ DNS_CHOICES = (
+ ('global','global'),('internal','ANL internal'),
+ ('private','private')
+ )
+ # FIXME: The new admin interface has change a lot.
+ #ip = models.ForeignKey(IP, edit_inline=models.TABULAR, num_in_admin=1)
+ ip = models.ForeignKey(IP)
+ # FIXME: The new admin interface has change a lot.
+ #name = models.CharField(max_length=64, core=True)
+ name = models.CharField(max_length=64)
+ dns_view = models.CharField(max_length=16, choices=DNS_CHOICES)
+ only = models.BooleanField(blank=True)
+ mxs = models.ManyToManyField(MX)
+
+ def __str__(self):
+ return self.name
+
+ class Admin:
+ pass
+
+class CName(models.Model):
+ # FIXME: The new admin interface has change a lot.
+ #name = models.ForeignKey(Name, edit_inline=models.TABULAR, num_in_admin=1)
+ name = models.ForeignKey(Name)
+ # FIXME: The new admin interface has change a lot.
+ #cname = models.CharField(max_length=64, core=True)
+ cname = models.CharField(max_length=64)
+
+ def __str__(self):
+ return self.cname
+
+ class Admin:
+ pass
+
+class Nameserver(models.Model):
+ name = models.CharField(max_length=64, blank=True)
+
+ def __str__(self):
+ return self.name
+
+ class Admin:
+ pass
+
+class ZoneAddress(models.Model):
+ ip_addr = models.IPAddressField(blank=True)
+
+ def __str__(self):
+ return self.ip_addr
+
+ class Admin:
+ pass
+
+class Zone(models.Model):
+ zone = models.CharField(max_length=64)
+ serial = models.IntegerField()
+ admin = models.CharField(max_length=64)
+ primary_master = models.CharField(max_length=64)
+ expire = models.IntegerField()
+ retry = models.IntegerField()
+ refresh = models.IntegerField()
+ ttl = models.IntegerField()
+ nameservers = models.ManyToManyField(Nameserver, blank=True)
+ mxs = models.ManyToManyField(MX, blank=True)
+ addresses = models.ManyToManyField(ZoneAddress, blank=True)
+ aux = models.TextField(blank=True)
+
+ def __str__(self):
+ return self.zone
+
+ class Admin:
+ pass
+
+class Log(models.Model):
+ # FIXME: Proposal hostname = models.ForeignKey(Host)
+ hostname = models.CharField(max_length=64)
+ date = models.DateTimeField(auto_now=True, auto_now_add=True)
+ log = models.TextField()
+
+ def __str__(self):
+ return self.hostname
+
+class ZoneLog(models.Model):
+ zone = models.CharField(max_length=64)
+ date = models.DateTimeField(auto_now=True, auto_now_add=True)
+ log = models.TextField()
+
+ def __str__(self):
+ return self.zone
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/sql/zone.sql b/src/lib/Bcfg2/Server/Hostbase/hostbase/sql/zone.sql
new file mode 100644
index 000000000..b78187ab2
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/sql/zone.sql
@@ -0,0 +1,2 @@
+INSERT INTO hostbase_zone (zone, serial, admin, primary_master, expire, retry, refresh, ttl, aux)
+VALUES ('.rev', 0, '', '', 1209600, 1800, 7200, 7200, ''); \ No newline at end of file
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/urls.py b/src/lib/Bcfg2/Server/Hostbase/hostbase/urls.py
new file mode 100644
index 000000000..0ee204abe
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/urls.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+from django.contrib.auth.decorators import login_required
+from django.core.urlresolvers import reverse
+from django.views.generic.create_update import create_object, update_object, delete_object
+from django.views.generic.list_detail import object_detail, object_list
+
+from models import Host, Zone, Log
+
+host_detail_dict = {
+ 'queryset':Host.objects.all(),
+ 'template_name':'host.html',
+ 'template_object_name':'host',
+}
+
+host_delete_dict = {
+ 'model':Host,
+ 'post_delete_redirect':'/',
+}
+
+host_log_detail_dict = host_detail_dict.copy()
+host_log_detail_dict['template_name'] = 'logviewer.html'
+
+host_dns_detail_dict = host_detail_dict.copy()
+host_dns_detail_dict['template_name'] = 'dns.html'
+
+zone_new_dict = {
+ 'model':Zone,
+ 'template_name':'zonenew.html',
+ 'post_save_redirect':'../%(id)s',
+}
+
+zones_list_dict = {
+ 'queryset':Zone.objects.all(),
+ 'template_name':'zones.html',
+ 'template_object_name':'zone',
+}
+
+zone_detail_dict = {
+ 'queryset':Zone.objects.all(),
+ 'template_name':'zoneview.html',
+ 'template_object_name':'zone',
+}
+
+urlpatterns = patterns('',
+ (r'^(?P<object_id>\d+)/$', object_detail, host_detail_dict, 'host_detail'),
+ (r'^zones/new/$', login_required(create_object), zone_new_dict, 'zone_new'),
+ (r'^zones/(?P<object_id>\d+)/edit', login_required(update_object), zone_new_dict, 'zone_edit'),
+ (r'^zones/$', object_list, zones_list_dict, 'zone_list'),
+ (r'^zones/(?P<object_id>\d+)/$', object_detail, zone_detail_dict, 'zone_detail'),
+ (r'^zones/(?P<object_id>\d+)/$', object_detail, zone_detail_dict, 'zone_detail'),
+ (r'^\d+/logs/(?P<object_id>\d+)/', object_detail, { 'queryset':Log.objects.all() }, 'log_detail'),
+ (r'^(?P<object_id>\d+)/logs/', object_detail, host_log_detail_dict, 'host_log_list'),
+ (r'^(?P<object_id>\d+)/dns', object_detail, host_dns_detail_dict, 'host_dns_list'),
+ (r'^(?P<object_id>\d+)/remove', login_required(delete_object), host_delete_dict, 'host_delete'),
+)
+
+urlpatterns += patterns('Bcfg2.Server.Hostbase.hostbase.views',
+ (r'^$', 'search'),
+ (r'^(?P<host_id>\d+)/edit', 'edit'),
+ (r'^(?P<host_id>\d+)/(?P<item>\D+)/(?P<item_id>\d+)/confirm', 'confirm'),
+ (r'^(?P<host_id>\d+)/(?P<item>\D+)/(?P<item_id>\d+)/(?P<name_id>\d+)/confirm', 'confirm'),
+ (r'^(?P<host_id>\d+)/dns/edit', 'dnsedit'),
+ (r'^new', 'new'),
+ (r'^(?P<host_id>\d+)/copy', 'copy'),
+# (r'^hostinfo', 'hostinfo'),
+ (r'^zones/(?P<zone_id>\d+)/(?P<item>\D+)/(?P<item_id>\d+)/confirm', 'confirm'),
+)
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/views.py b/src/lib/Bcfg2/Server/Hostbase/hostbase/views.py
new file mode 100644
index 000000000..57ef5eff8
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/views.py
@@ -0,0 +1,970 @@
+"""Views.py
+Contains all the views associated with the hostbase app
+Also has does form validation
+"""
+from django.http import HttpResponse, HttpResponseRedirect
+
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth import logout
+from django.template import RequestContext
+from Bcfg2.Server.Hostbase.hostbase.models import *
+from datetime import date
+from django.db import connection
+from django.shortcuts import render_to_response
+from django import forms
+from Bcfg2.Server.Hostbase import settings, regex
+import re, copy
+
+attribs = ['hostname', 'whatami', 'netgroup', 'security_class', 'support',
+ 'csi', 'printq', 'primary_user', 'administrator', 'location',
+ 'status', 'comments']
+
+zoneattribs = ['zone', 'admin', 'primary_master', 'expire', 'retry',
+ 'refresh', 'ttl', 'aux']
+
+dispatch = {'mac_addr':'i.mac_addr LIKE \'%%%%%s%%%%\'',
+ 'ip_addr':'p.ip_addr LIKE \'%%%%%s%%%%\'',
+ 'name':'n.name LIKE \'%%%%%s%%%%\'',
+## 'hostname':'n.name LIKE \'%%%%%s%%%%\'',
+## 'cname':'n.name LIKE \'%%%%%s%%%%\'',
+ 'mx':'m.mx LIKE \'%%%%%s%%%%\'',
+ 'dns_view':'n.dns_view = \'%s\'',
+ 'hdwr_type':'i.hdwr_type = \'%s\'',
+ 'dhcp':'i.dhcp = \'%s\''}
+
+def search(request):
+ """Search for hosts in the database
+ If more than one field is entered, logical AND is used
+ """
+ if 'sub' in request.GET:
+ querystring = """SELECT DISTINCT h.hostname, h.id, h.status
+ FROM (((((hostbase_host h
+ INNER JOIN hostbase_interface i ON h.id = i.host_id)
+ INNER JOIN hostbase_ip p ON i.id = p.interface_id)
+ INNER JOIN hostbase_name n ON p.id = n.ip_id)
+ INNER JOIN hostbase_name_mxs x ON n.id = x.name_id)
+ INNER JOIN hostbase_mx m ON m.id = x.mx_id)
+ LEFT JOIN hostbase_cname c ON n.id = c.name_id
+ WHERE """
+
+ _and = False
+ for field in request.POST:
+ if request.POST[field] and field == 'hostname':
+ if _and:
+ querystring += ' AND '
+ querystring += 'n.name LIKE \'%%%%%s%%%%\' or c.cname LIKE \'%%%%%s%%%%\'' % (request.POST[field], request.POST[field])
+ _and = True
+ elif request.POST[field] and field in dispatch:
+ if _and:
+ querystring += ' AND '
+ querystring += dispatch[field] % request.POST[field]
+ _and = True
+ elif request.POST[field]:
+ if _and:
+ querystring += ' AND '
+ querystring += "h.%s LIKE \'%%%%%s%%%%\'" % (field, request.POST[field])
+ _and = True
+
+ if not _and:
+ cursor = connection.cursor()
+ cursor.execute("""SELECT hostname, id, status
+ FROM hostbase_host ORDER BY hostname""")
+ results = cursor.fetchall()
+ else:
+ querystring += " ORDER BY h.hostname"
+ cursor = connection.cursor()
+ cursor.execute(querystring)
+ results = cursor.fetchall()
+
+ return render_to_response('results.html',
+ {'hosts': results,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+ else:
+ return render_to_response('search.html',
+ {'TYPE_CHOICES': Interface.TYPE_CHOICES,
+ 'DNS_CHOICES': Name.DNS_CHOICES,
+ 'yesno': [(1, 'yes'), (0, 'no')],
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+
+def gethostdata(host_id, dnsdata=False):
+ """Grabs the necessary data about a host
+ Replaces a lot of repeated code"""
+ hostdata = {}
+ hostdata['ips'] = {}
+ hostdata['names'] = {}
+ hostdata['cnames'] = {}
+ hostdata['mxs'] = {}
+ hostdata['host'] = Host.objects.get(id=host_id)
+ hostdata['interfaces'] = hostdata['host'].interface_set.all()
+ for interface in hostdata['interfaces']:
+ hostdata['ips'][interface.id] = interface.ip_set.all()
+ if dnsdata:
+ for ip in hostdata['ips'][interface.id]:
+ hostdata['names'][ip.id] = ip.name_set.all()
+ for name in hostdata['names'][ip.id]:
+ hostdata['cnames'][name.id] = name.cname_set.all()
+ hostdata['mxs'][name.id] = name.mxs.all()
+ return hostdata
+
+def fill(template, hostdata, dnsdata=False):
+ """Fills a generic template
+ Replaces a lot of repeated code"""
+ if dnsdata:
+ template.names = hostdata['names']
+ template.cnames = hostdata['cnames']
+ template.mxs = hostdata['mxs']
+ template.host = hostdata['host']
+ template.interfaces = hostdata['interfaces']
+ template.ips = hostdata['ips']
+ return template
+
+def edit(request, host_id):
+ """edit general host information"""
+ manipulator = Host.ChangeManipulator(host_id)
+ changename = False
+ if request.method == 'POST':
+ host = Host.objects.get(id=host_id)
+ before = host.__dict__.copy()
+ if request.POST['hostname'] != host.hostname:
+ oldhostname = host.hostname.split(".")[0]
+ changename = True
+ interfaces = host.interface_set.all()
+ old_interfaces = [interface.__dict__.copy() for interface in interfaces]
+
+ new_data = request.POST.copy()
+
+ errors = manipulator.get_validation_errors(new_data)
+ if not errors:
+
+ # somehow keep track of multiple interface change manipulators
+ # as well as multiple ip chnage manipulators??? (add manipulators???)
+ # change to many-to-many??????
+
+ # dynamically look up mx records?
+ text = ''
+
+ for attrib in attribs:
+ if host.__dict__[attrib] != request.POST[attrib]:
+ text = do_log(text, attrib, host.__dict__[attrib], request.POST[attrib])
+ host.__dict__[attrib] = request.POST[attrib]
+
+ if 'expiration_date' in request.POST:
+ ymd = request.POST['expiration_date'].split("-")
+ if date(int(ymd[0]), int(ymd[1]), int(ymd[2])) != host.__dict__['expiration_date']:
+ text = do_log(text, 'expiration_date', host.__dict__['expiration_date'],
+ request.POST['expiration_date'])
+ host.__dict__['expiration_date'] = date(int(ymd[0]), int(ymd[1]), int(ymd[2]))
+
+ for inter in interfaces:
+ changetype = False
+ ips = IP.objects.filter(interface=inter.id)
+ if inter.mac_addr != request.POST['mac_addr%d' % inter.id]:
+ text = do_log(text, 'mac_addr', inter.mac_addr, request.POST['mac_addr%d' % inter.id])
+ inter.mac_addr = request.POST['mac_addr%d' % inter.id].lower().replace('-',':')
+ if inter.hdwr_type != request.POST['hdwr_type%d' % inter.id]:
+ oldtype = inter.hdwr_type
+ text = do_log(text, 'hdwr_type', oldtype, request.POST['hdwr_type%d' % inter.id])
+ inter.hdwr_type = request.POST['hdwr_type%d' % inter.id]
+ changetype = True
+ if (('dhcp%d' % inter.id) in request.POST and not inter.dhcp or
+ not ('dhcp%d' % inter.id) in request.POST and inter.dhcp):
+ text = do_log(text, 'dhcp', inter.dhcp, int(not inter.dhcp))
+ inter.dhcp = not inter.dhcp
+ for ip in ips:
+ names = ip.name_set.all()
+ if not ip.ip_addr == request.POST['ip_addr%d' % ip.id]:
+ oldip = ip.ip_addr
+ oldsubnet = oldip.split(".")[2]
+ ip.ip_addr = request.POST['ip_addr%d' % ip.id]
+ ip.save()
+ text = do_log(text, 'ip_addr', oldip, ip.ip_addr)
+ for name in names:
+ if name.name.split(".")[0].endswith('-%s' % oldsubnet):
+ name.name = name.name.replace('-%s' % oldsubnet, '-%s' % ip.ip_addr.split(".")[2])
+ name.save()
+ if changetype:
+ for name in names:
+ if name.name.split(".")[0].endswith('-%s' % oldtype):
+ name.name = name.name.replace('-%s' % oldtype, '-%s' % inter.hdwr_type)
+ name.save()
+ if changename:
+ for name in names:
+ if name.name.startswith(oldhostname):
+ name.name = name.name.replace(oldhostname, host.hostname.split(".")[0])
+ name.save()
+ if request.POST['%dip_addr' % inter.id]:
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_ip = IP(interface=inter, ip_addr=request.POST['%dip_addr' % inter.id])
+ new_ip.save()
+ text = do_log(text, '*new*', 'ip_addr', new_ip.ip_addr)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ inter.save()
+ if request.POST['mac_addr_new']:
+ new_inter = Interface(host=host,
+ mac_addr=request.POST['mac_addr_new'].lower().replace('-',':'),
+ hdwr_type=request.POST['hdwr_type_new'],
+ dhcp=request.POST['dhcp_new'])
+ text = do_log(text, '*new*', 'mac_addr', new_inter.mac_addr)
+ new_inter.save()
+ if request.POST['mac_addr_new'] and request.POST['ip_addr_new']:
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
+ new_ip.save()
+ text = do_log(text, '*new*', 'ip_addr', new_ip.ip_addr)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['ip_addr_new'] and not request.POST['mac_addr_new']:
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_inter = Interface(host=host, mac_addr="",
+ hdwr_type=request.POST['hdwr_type_new'],
+ dhcp=False)
+ new_inter.save()
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
+ new_ip.save()
+ text = do_log(text, '*new*', 'ip_addr', new_ip.ip_addr)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if text:
+ log = Log(hostname=host.hostname, log=text)
+ log.save()
+ host.save()
+ return HttpResponseRedirect('/hostbase/%s/' % host.id)
+ else:
+ return render_to_response('errors.html',
+ {'failures': errors,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+ else:
+ host = Host.objects.get(id=host_id)
+ interfaces = []
+ for interface in host.interface_set.all():
+ interfaces.append([interface, interface.ip_set.all()])
+ return render_to_response('edit.html',
+ {'host': host,
+ 'interfaces': interfaces,
+ 'TYPE_CHOICES': Interface.TYPE_CHOICES,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+def confirm(request, item, item_id, host_id=None, name_id=None, zone_id=None):
+ """Asks if the user is sure he/she wants to remove an item"""
+ if 'sub' in request.GET:
+ if item == 'interface':
+ for ip in Interface.objects.get(id=item_id).ip_set.all():
+ for name in ip.name_set.all():
+ name.cname_set.all().delete()
+ ip.name_set.all().delete()
+ Interface.objects.get(id=item_id).ip_set.all().delete()
+ Interface.objects.get(id=item_id).delete()
+ elif item=='ip':
+ for name in IP.objects.get(id=item_id).name_set.all():
+ name.cname_set.all().delete()
+ IP.objects.get(id=item_id).name_set.all().delete()
+ IP.objects.get(id=item_id).delete()
+ elif item=='cname':
+ CName.objects.get(id=item_id).delete()
+ elif item=='mx':
+ mx = MX.objects.get(id=item_id)
+ Name.objects.get(id=name_id).mxs.remove(mx)
+ elif item=='name':
+ Name.objects.get(id=item_id).cname_set.all().delete()
+ Name.objects.get(id=item_id).delete()
+ elif item=='nameserver':
+ nameserver = Nameserver.objects.get(id=item_id)
+ Zone.objects.get(id=zone_id).nameservers.remove(nameserver)
+ elif item=='zonemx':
+ mx = MX.objects.get(id=item_id)
+ Zone.objects.get(id=zone_id).mxs.remove(mx)
+ elif item=='address':
+ address = ZoneAddress.objects.get(id=item_id)
+ Zone.objects.get(id=zone_id).addresses.remove(address)
+ if item == 'cname' or item == 'mx' or item == 'name':
+ return HttpResponseRedirect('/hostbase/%s/dns/edit' % host_id)
+ elif item == 'nameserver' or item == 'zonemx' or item == 'address':
+ return HttpResponseRedirect('/hostbase/zones/%s/edit' % zone_id)
+ else:
+ return HttpResponseRedirect('/hostbase/%s/edit' % host_id)
+ else:
+ interface = None
+ ips = []
+ names = []
+ cnames = []
+ mxs = []
+ zonemx = None
+ nameserver = None
+ address = None
+ if item == 'interface':
+ interface = Interface.objects.get(id=item_id)
+ ips = interface.ip_set.all()
+ for ip in ips:
+ for name in ip.name_set.all():
+ names.append((ip.id, name))
+ for cname in name.cname_set.all():
+ cnames.append((name.id, cname))
+ for mx in name.mxs.all():
+ mxs.append((name.id, mx))
+ elif item=='ip':
+ ips = [IP.objects.get(id=item_id)]
+ for name in ips[0].name_set.all():
+ names.append((ips[0].id, name))
+ for cname in name.cname_set.all():
+ cnames.append((name.id, cname))
+ for mx in name.mxs.all():
+ mxs.append((name.id, mx))
+ elif item=='name':
+ names = [Name.objects.get(id=item_id)]
+ for cname in names[0].cname_set.all():
+ cnames.append((names[0].id, cname))
+ for mx in names[0].mxs.all():
+ mxs.append((names[0].id, mx))
+ elif item=='cname':
+ cnames = [CName.objects.get(id=item_id)]
+ elif item=='mx':
+ mxs = [MX.objects.get(id=item_id)]
+ elif item=='zonemx':
+ zonemx = MX.objects.get(id=item_id)
+ elif item=='nameserver':
+ nameserver = Nameserver.objects.get(id=item_id)
+ elif item=='address':
+ address = ZoneAddress.objects.get(id=item_id)
+ return render_to_response('confirm.html',
+ {'interface': interface,
+ 'ips': ips,
+ 'names': names,
+ 'cnames': cnames,
+ 'id': item_id,
+ 'type': item,
+ 'host_id': host_id,
+ 'mxs': mxs,
+ 'zonemx': zonemx,
+ 'nameserver': nameserver,
+ 'address': address,
+ 'zone_id': zone_id,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+def dnsedit(request, host_id):
+ """Edits specific DNS information
+ Data is validated before committed to the database"""
+ text = ''
+ if 'sub' in request.GET:
+ hostdata = gethostdata(host_id, True)
+ for ip in hostdata['names']:
+ ipaddr = IP.objects.get(id=ip)
+ ipaddrstr = ipaddr.__str__()
+ for name in hostdata['cnames']:
+ for cname in hostdata['cnames'][name]:
+ if regex.host.match(request.POST['cname%d' % cname.id]):
+ text = do_log(text, 'cname', cname.cname, request.POST['cname%d' % cname.id])
+ cname.cname = request.POST['cname%d' % cname.id]
+ cname.save()
+ for name in hostdata['mxs']:
+ for mx in hostdata['mxs'][name]:
+ if (mx.priority != request.POST['priority%d' % mx.id] and mx.mx != request.POST['mx%d' % mx.id]):
+ text = do_log(text, 'mx', ' '.join([str(mx.priority), str(mx.mx)]),
+ ' '.join([request.POST['priority%d' % mx.id], request.POST['mx%d' % mx.id]]))
+ nameobject = Name.objects.get(id=name)
+ nameobject.mxs.remove(mx)
+ newmx, created = MX.objects.get_or_create(priority=request.POST['priority%d' % mx.id], mx=request.POST['mx%d' % mx.id])
+ if created:
+ newmx.save()
+ nameobject.mxs.add(newmx)
+ nameobject.save()
+ for name in hostdata['names'][ip]:
+ name.name = request.POST['name%d' % name.id]
+ name.dns_view = request.POST['dns_view%d' % name.id]
+ if (request.POST['%dcname' % name.id] and
+ regex.host.match(request.POST['%dcname' % name.id])):
+ cname = CName(name=name,
+ cname=request.POST['%dcname' % name.id])
+ text = do_log(text, '*new*', 'cname', cname.cname)
+ cname.save()
+ if (request.POST['%dpriority' % name.id] and
+ request.POST['%dmx' % name.id]):
+ mx, created = MX.objects.get_or_create(priority=request.POST['%dpriority' % name.id],
+ mx=request.POST['%dmx' % name.id])
+ if created:
+ mx.save()
+ text = do_log(text, '*new*', 'mx',
+ ' '.join([request.POST['%dpriority' % name.id],
+ request.POST['%dmx' % name.id]]))
+ name.mxs.add(mx)
+ name.save()
+ if request.POST['%sname' % ipaddrstr]:
+ name = Name(ip=ipaddr,
+ dns_view=request.POST['%sdns_view' % ipaddrstr],
+ name=request.POST['%sname' % ipaddrstr], only=False)
+ text = do_log(text, '*new*', 'name', name.name)
+ name.save()
+ if (request.POST['%scname' % ipaddrstr] and
+ regex.host.match(request.POST['%scname' % ipaddrstr])):
+ cname = CName(name=name,
+ cname=request.POST['%scname' % ipaddrstr])
+ text = do_log(text, '*new*', 'cname', cname.cname)
+ cname.save()
+ if (request.POST['%smx' % ipaddrstr] and
+ request.POST['%spriority' % ipaddrstr]):
+ mx, created = MX.objects.get_or_create(priority=request.POST['%spriority' % ipaddrstr],
+ mx=request.POST['%smx' % ipaddrstr])
+ if created:
+ mx.save()
+ text = do_log(text, '*new*', 'mx',
+ ' '.join([request.POST['%spriority' % ipaddrstr], request.POST['%smx' % ipaddrstr]]))
+ name.mxs.add(mx)
+ if text:
+ log = Log(hostname=hostdata['host'].hostname, log=text)
+ log.save()
+ return HttpResponseRedirect('/hostbase/%s/dns' % host_id)
+ else:
+ host = Host.objects.get(id=host_id)
+ ips = []
+ info = []
+ cnames = []
+ mxs = []
+ interfaces = host.interface_set.all()
+ for interface in host.interface_set.all():
+ ips.extend(interface.ip_set.all())
+ for ip in ips:
+ info.append([ip, ip.name_set.all()])
+ for name in ip.name_set.all():
+ cnames.extend(name.cname_set.all())
+ mxs.append((name.id, name.mxs.all()))
+ return render_to_response('dnsedit.html',
+ {'host': host,
+ 'info': info,
+ 'cnames': cnames,
+ 'mxs': mxs,
+ 'request': request,
+ 'interfaces': interfaces,
+ 'DNS_CHOICES': Name.DNS_CHOICES,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+def new(request):
+ """Function for creating a new host in hostbase
+ Data is validated before committed to the database"""
+ if 'sub' in request.GET:
+ try:
+ Host.objects.get(hostname=request.POST['hostname'].lower())
+ return render_to_response('errors.html',
+ {'failures': ['%s already exists in hostbase' % request.POST['hostname']],
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+ except:
+ pass
+ if not validate(request, True):
+ if not request.POST['ip_addr_new'] and not request.POST['ip_addr_new2']:
+ return render_to_response('errors.html',
+ {'failures': ['ip_addr: You must enter an ip address'],
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+ host = Host()
+ # this is the stuff that validate() should take care of
+ # examine the check boxes for any changes
+ host.outbound_smtp = 'outbound_smtp' in request.POST
+ for attrib in attribs:
+ if attrib in request.POST:
+ host.__dict__[attrib] = request.POST[attrib].lower()
+ if 'comments' in request.POST:
+ host.comments = request.POST['comments']
+ if 'expiration_date' in request.POST:
+# ymd = request.POST['expiration_date'].split("-")
+# host.__dict__['expiration_date'] = date(int(ymd[0]), int(ymd[1]), int(ymd[2]))
+ host.__dict__['expiration_date'] = date(2000, 1, 1)
+ host.status = 'active'
+ host.save()
+ else:
+ return render_to_response('errors.html',
+ {'failures': validate(request, True),
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+ if request.POST['mac_addr_new']:
+ new_inter = Interface(host=host,
+ mac_addr = request.POST['mac_addr_new'].lower().replace('-',':'),
+ hdwr_type = request.POST['hdwr_type_new'],
+ dhcp = 'dhcp_new' in request.POST)
+ new_inter.save()
+ if request.POST['mac_addr_new'] and request.POST['ip_addr_new']:
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
+# Change all this things. Use a "post_save" signal handler for model Host to create all sociate models
+# and use a generi view.
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name, dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['ip_addr_new'] and not request.POST['mac_addr_new']:
+ new_inter = Interface(host=host,
+ mac_addr="",
+ hdwr_type=request.POST['hdwr_type_new'],
+ dhcp=False)
+ new_inter.save()
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['mac_addr_new2']:
+ new_inter = Interface(host=host,
+ mac_addr = request.POST['mac_addr_new2'].lower().replace('-',':'),
+ hdwr_type = request.POST['hdwr_type_new2'],
+ dhcp = 'dhcp_new2' in request.POST)
+ new_inter.save()
+ if request.POST['mac_addr_new2'] and request.POST['ip_addr_new2']:
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['ip_addr_new2'] and not request.POST['mac_addr_new2']:
+ new_inter = Interface(host=host,
+ mac_addr="",
+ hdwr_type=request.POST['hdwr_type_new2'],
+ dhcp=False)
+ new_inter.save()
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ host.save()
+ return HttpResponseRedirect('/hostbase/%s/' % host.id)
+ else:
+ return render_to_response('new.html',
+ {'TYPE_CHOICES': Interface.TYPE_CHOICES,
+ 'NETGROUP_CHOICES': Host.NETGROUP_CHOICES,
+ 'CLASS_CHOICES': Host.CLASS_CHOICES,
+ 'SUPPORT_CHOICES': Host.SUPPORT_CHOICES,
+ 'WHATAMI_CHOICES': Host.WHATAMI_CHOICES,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+def copy(request, host_id):
+ """Function for creating a new host in hostbase
+ Data is validated before committed to the database"""
+ if 'sub' in request.GET:
+ try:
+ Host.objects.get(hostname=request.POST['hostname'].lower())
+ return render_to_response('errors.html',
+ {'failures': ['%s already exists in hostbase' % request.POST['hostname']],
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+ except:
+ pass
+ if not validate(request, True):
+ if not request.POST['ip_addr_new'] and not request.POST['ip_addr_new2']:
+ return render_to_response('errors.html',
+ {'failures': ['ip_addr: You must enter an ip address'],
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+ host = Host()
+ # this is the stuff that validate() should take care of
+ # examine the check boxes for any changes
+ host.outbound_smtp = 'outbound_smtp' in request.POST
+ for attrib in attribs:
+ if attrib in request.POST:
+ host.__dict__[attrib] = request.POST[attrib].lower()
+ if 'comments' in request.POST:
+ host.comments = request.POST['comments']
+ if 'expiration_date' in request.POST:
+# ymd = request.POST['expiration_date'].split("-")
+# host.__dict__['expiration_date'] = date(int(ymd[0]), int(ymd[1]), int(ymd[2]))
+ host.__dict__['expiration_date'] = date(2000, 1, 1)
+ host.status = 'active'
+ host.save()
+ else:
+ return render_to_response('errors.html',
+ {'failures': validate(request, True),
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+ if request.POST['mac_addr_new']:
+ new_inter = Interface(host=host,
+ mac_addr = request.POST['mac_addr_new'].lower().replace('-',':'),
+ hdwr_type = request.POST['hdwr_type_new'],
+ dhcp = 'dhcp_new' in request.POST)
+ new_inter.save()
+ if request.POST['mac_addr_new'] and request.POST['ip_addr_new']:
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name, dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['ip_addr_new'] and not request.POST['mac_addr_new']:
+ new_inter = Interface(host=host,
+ mac_addr="",
+ hdwr_type=request.POST['hdwr_type_new'],
+ dhcp=False)
+ new_inter.save()
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['mac_addr_new2']:
+ new_inter = Interface(host=host,
+ mac_addr = request.POST['mac_addr_new2'].lower().replace('-',':'),
+ hdwr_type = request.POST['hdwr_type_new2'],
+ dhcp = 'dhcp_new2' in request.POST)
+ new_inter.save()
+ if request.POST['mac_addr_new2'] and request.POST['ip_addr_new2']:
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ if request.POST['ip_addr_new2'] and not request.POST['mac_addr_new2']:
+ new_inter = Interface(host=host,
+ mac_addr="",
+ hdwr_type=request.POST['hdwr_type_new2'],
+ dhcp=False)
+ new_inter.save()
+ new_ip = IP(interface=new_inter, ip_addr=request.POST['ip_addr_new2'])
+ new_ip.save()
+ mx, created = MX.objects.get_or_create(priority=settings.PRIORITY, mx=settings.DEFAULT_MX)
+ if created:
+ mx.save()
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_ip.ip_addr.split(".")[2]])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ new_name = "-".join([host.hostname.split(".")[0],
+ new_inter.hdwr_type])
+ new_name += "." + host.hostname.split(".", 1)[1]
+ name = Name(ip=new_ip, name=new_name,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ name = Name(ip=new_ip, name=host.hostname,
+ dns_view='global', only=False)
+ name.save()
+ name.mxs.add(mx)
+ host.save()
+ return HttpResponseRedirect('/hostbase/%s/' % host.id)
+ else:
+ host = Host.objects.get(id=host_id)
+ return render_to_response('copy.html',
+ {'host': host,
+ 'TYPE_CHOICES': Interface.TYPE_CHOICES,
+ 'NETGROUP_CHOICES': Host.NETGROUP_CHOICES,
+ 'CLASS_CHOICES': Host.CLASS_CHOICES,
+ 'SUPPORT_CHOICES': Host.SUPPORT_CHOICES,
+ 'WHATAMI_CHOICES': Host.WHATAMI_CHOICES,
+ 'logged_in': request.session.get('_auth_user_id', False)},
+ context_instance = RequestContext(request))
+
+# FIXME: delete all this things in a signal handler "pre_delete"
+#def remove(request, host_id):
+# host = Host.objects.get(id=host_id)
+# if 'sub' in request:
+# for interface in host.interface_set.all():
+# for ip in interface.ip_set.all():
+# for name in ip.name_set.all():
+# name.cname_set.all().delete()
+# ip.name_set.all().delete()
+# interface.ip_set.all().delete()
+# interface.delete()
+# host.delete()
+
+def validate(request, new=False, host_id=None):
+ """Function for checking form data"""
+ failures = []
+ if (request.POST['expiration_date']
+ and regex.date.match(request.POST['expiration_date'])):
+ try:
+ (year, month, day) = request.POST['expiration_date'].split("-")
+ date(int(year), int(month), int(day))
+ except (ValueError):
+ failures.append('expiration_date')
+ elif request.POST['expiration_date']:
+ failures.append('expiration_date')
+
+ if not (request.POST['hostname']
+ and regex.host.match(request.POST['hostname'])):
+ failures.append('hostname')
+
+## if not regex.printq.match(request.POST['printq']) and request.POST['printq']:
+## failures.append('printq')
+
+## if not regex.user.match(request.POST['primary_user']):
+## failures.append('primary_user')
+
+## if (not regex.user.match(request.POST['administrator'])
+## and request.POST['administrator']):
+## failures.append('administrator')
+
+## if not (request.POST['location']
+## and regex.location.match(request.POST['location'])):
+## failures.append('location')
+
+ if new:
+ if (not regex.macaddr.match(request.POST['mac_addr_new'])
+ and request.POST['mac_addr_new']):
+ failures.append('mac_addr (#1)')
+ if ((request.POST['mac_addr_new'] or request.POST['ip_addr_new']) and
+ not 'hdwr_type_new' in request.REQUEST):
+ failures.append('hdwr_type (#1)')
+ if ((request.POST['mac_addr_new2'] or request.POST['ip_addr_new2']) and
+ not 'hdwr_type_new2' in request.REQUEST):
+ failures.append('hdwr_type (#2)')
+
+ if (not regex.macaddr.match(request.POST['mac_addr_new2'])
+ and request.POST['mac_addr_new2']):
+ failures.append('mac_addr (#2)')
+
+ if (not regex.ipaddr.match(request.POST['ip_addr_new'])
+ and request.POST['ip_addr_new']):
+ failures.append('ip_addr (#1)')
+ if (not regex. ipaddr.match(request.POST['ip_addr_new2'])
+ and request.POST['ip_addr_new2']):
+ failures.append('ip_addr (#2)')
+
+ [failures.append('ip_addr (#1)') for number in
+ request.POST['ip_addr_new'].split(".")
+ if number.isdigit() and int(number) > 255
+ and 'ip_addr (#1)' not in failures]
+ [failures.append('ip_addr (#2)') for number in
+ request.POST['ip_addr_new2'].split(".")
+ if number.isdigit() and int(number) > 255
+ and 'ip_addr (#2)' not in failures]
+
+ elif host_id:
+ interfaces = Interface.objects.filter(host=host_id)
+ for interface in interfaces:
+ if (not regex.macaddr.match(request.POST['mac_addr%d' % interface.id])
+ and request.POST['mac_addr%d' % interface.id]):
+ failures.append('mac_addr (%s)' % request.POST['mac_addr%d' % interface.id])
+ for ip in interface.ip_set.all():
+ if not regex.ipaddr.match(request.POST['ip_addr%d' % ip.id]):
+ failures.append('ip_addr (%s)' % request.POST['ip_addr%d' % ip.id])
+ [failures.append('ip_addr (%s)' % request.POST['ip_addr%d' % ip.id])
+ for number in request.POST['ip_addr%d' % ip.id].split(".")
+ if (number.isdigit() and int(number) > 255 and
+ 'ip_addr (%s)' % request.POST['ip_addr%d' % ip.id] not in failures)]
+ if (request.POST['%dip_addr' % interface.id]
+ and not regex.ipaddr.match(request.POST['%dip_addr' % interface.id])):
+ failures.append('ip_addr (%s)' % request.POST['%dip_addr' % interface.id])
+ if (request.POST['mac_addr_new']
+ and not regex.macaddr.match(request.POST['mac_addr_new'])):
+ failures.append('mac_addr (%s)' % request.POST['mac_addr_new'])
+ if (request.POST['ip_addr_new']
+ and not regex.ipaddr.match(request.POST['ip_addr_new'])):
+ failures.append('ip_addr (%s)' % request.POST['ip_addr_new'])
+
+ if not failures:
+ return 0
+ return failures
+
+def do_log(text, attribute, previous, new):
+ if previous != new:
+ text += "%-20s%-20s -> %s\n" % (attribute, previous, new)
+ return text
+
+## login required stuff
+## uncomment the views below that you would like to restrict access to
+
+## uncomment the lines below this point to restrict access to pages that modify the database
+## anonymous users can still view data in Hostbase
+
+edit = login_required(edit)
+confirm = login_required(confirm)
+dnsedit = login_required(dnsedit)
+new = login_required(new)
+copy = login_required(copy)
+#remove = login_required(remove)
+#zoneedit = login_required(zoneedit)
+#zonenew = login_required(zonenew)
+
+## uncomment the lines below this point to restrict access to all of hostbase
+
+## search = login_required(search)
+## look = login_required(look)
+## dns = login_required(dns)
+## zones = login_required(zones)
+## zoneview = login_required(zoneview)
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/base.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/base.html
new file mode 100644
index 000000000..1d7c5565b
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/base.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>{% block title %}BCFG2 - Hostbase{% endblock %}</title>
+ <link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}/boxypastel.css" />
+ <link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}/base.css" />
+ <!--<script type="text/javascript" src="http://hostbase.mcs.anl.gov/site_media/main.js"> -->
+ {% block extra_header_info %}{% endblock %}
+</head>
+
+<body>
+ <div id="header">
+ <div id="branding">
+ <h1>BCFG2</h1>
+ </div>
+ <div id="user-tools">...Change is Coming...</div>
+ </div>
+ <div id="sidebar">
+ {% block sidebar %}
+ <ul class="sidebar">
+ </ul>
+ {% endblock %}
+ </div>
+
+ <div id="content-main">
+ <div id="container">
+ {% block pagebanner %}{% endblock %}
+ {% block content %}{% endblock %}
+
+ </div>
+ </div>
+</body>
+</html>
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/confirm.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/confirm.html
new file mode 100644
index 000000000..ca8b0cc07
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/confirm.html
@@ -0,0 +1,117 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Confirm Removal</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<form name="input" action="confirm.html?sub=true" method="post">
+Are you sure you want to remove these items?
+
+{% if interface %}
+<ul>
+<li> interface: {{ interface.mac_addr }} </li>
+{% endif %}
+
+
+{% if ips %}
+<ul>
+{% for ip in ips %}
+<li> ip: {{ ip.ip_addr }} </li>
+<ul>
+{% for name in names %}
+{% ifequal name.0 ip.id %}
+<li> name: {{ name.1.name }} </li>
+<ul>
+{% endifequal %}
+{% for cname in cnames %}
+{% ifequal cname.0 name.1.id %}
+<li> cname: {{ cname.1.name }} </li>
+{% endifequal %}
+{% endfor %}
+</ul>
+<ul>
+{% for mx in mxs %}
+{% ifequal mx.0 name.1.id %}
+<li> mx: {{ mx.1.priority }} {{ mx.1.mx }} </li>
+{% endifequal %}
+{% endfor %}
+</ul>
+{% endfor %}
+</ul>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% if names and not ips %}
+<ul>
+{% for name in names %}
+<li> name: {{ name.name }} </li>
+<ul>
+{% for cname in cnames %}
+{% ifequal cname.0 name.id %}
+<li> cname: {{ cname.1.cname }} </li>
+{% endifequal %}
+{% endfor %}
+</ul>
+<ul>
+{% for mx in mxs %}
+{% ifequal mx.0 name.id %}
+<li> mx: {{ mx.1.priority }} {{ mx.1.mx }} </li>
+{% endifequal %}
+{% endfor %}
+</ul>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% if cnames and not names %}
+<ul>
+{% for cname in cnames %}
+<li> cname: {{ cname.cname }} </li>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% if mxs and not names %}
+<ul>
+{% for mx in mxs %}
+<li> mx: {{ mx.priority }} {{ mx.mx }} </li>
+{% endfor %}
+</ul>
+{% endif %}
+
+{% if interface %}
+</ul>
+{% endif %}
+
+{% if zone_id %}
+<ul>
+{% ifequal type 'zonemx' %}
+<li> mx: {{ zonemx.priority }} {{ zonemx.mx }} </li>
+{% endifequal %}
+
+{% ifequal type 'nameserver' %}
+<li> nameserver: {{ nameserver.name }} </li>
+{% endifequal %}
+
+{% ifequal type 'address' %}
+<li> address: {{ address.ip_addr }} </li>
+{% endifequal %}
+</ul>
+{% endif %}
+
+<input type="submit" value="confirm">
+<input type="reset" value="cancel" onclick="history.back()">
+</form>
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/copy.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/copy.html
new file mode 100644
index 000000000..400ef58f2
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/copy.html
@@ -0,0 +1,122 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>new host information</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+<a href="/hostbase/" class="sidebar">search hostbase</a>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<form name="hostdata" action="?sub=true" method="post">
+<input type="hidden" name="host">
+<table border="0" width="100%">
+ <colgroup>
+ <col width="150">
+ <col width="*">
+ <tr> <td> <b>hostname</b></td>
+ <td> <input name="hostname" type="text" value="{{ host.hostname }}" ></td></tr>
+ <tr> <td> <b>whatami</b></td>
+ <td>
+ <select name="whatami">
+ {% for choice in WHATAMI_CHOICES %}
+ {% ifequal host.whatami choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected" >{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select>
+ </td></tr>
+ <tr> <td> <b>netgroup</b></td>
+ <td>
+ <select name="netgroup">
+ {% for choice in NETGROUP_CHOICES %}
+ {% ifequal host.netgroup choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected" >{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select>
+ </td></tr>
+ <tr> <td> <b>class</b></td>
+ <td>
+ <select name="security_class">
+ {% for choice in CLASS_CHOICES %}
+ {% ifequal host.security_class choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected" >{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select></td></tr>
+ <tr> <td> <b>support</b></td>
+ <td>
+ <select name="support">
+ {% for choice in SUPPORT_CHOICES %}
+ {% ifequal host.support choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected" >{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select></td></tr>
+ <tr> <td> <b>csi</b></td>
+ <td> <input name="csi" type="text" value="{{ host.csi }}" ></td></tr>
+ <tr> <td> <b>printq</b></td>
+ <td> <input name="printq" type="text" value="{{ host.printq }}" ></td></tr>
+ <tr> <td> <b>outbound_smtp</b></td>
+ <td>
+ {% if host.outbound_smtp %}
+ <input type="checkbox" name="outbound_smtp" checked="checked" ></td></tr>
+ {% else %}
+ <input type="checkbox" name="outbound_smtp" ></td></tr>
+ {% endif %}
+ <tr> <td> <b>primary_user</b></td>
+ <td> <input name="primary_user" type="text" size="32" value="{{ host.primary_user }}"> (email address)</td></tr>
+ <tr> <td> <b>administrator</b></td>
+ <td> <input name="administrator" type="text" size="32" value="{{ host.administrator }}"> (email address)</td></tr>
+ <tr> <td> <b>location</b></td>
+ <td> <input name="location" type="text" value="{{ host.location }}"></td></tr>
+ <tr> <td> <b>expiration_date</b></td>
+ <td> <input name="expiration_date" type="text" size="10" value="{{ host.expiration_date }}">YYYY-MM-DD</td></tr>
+ <tr> <td><br><b>Interface</b></td><td><br>
+ {% for choice in TYPE_CHOICES %}
+ <input type="radio" name="hdwr_type_new" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}
+ </td></tr>
+ <tr> <td> <b>dhcp</b></td>
+ <td>
+ <input type="checkbox" name="dhcp_new"></td></tr>
+ <tr> <td> <b>mac_addr</b></td>
+ <td> <input name="mac_addr_new" type="text"></td></tr>
+ <tr> <td> <b>ip_addr</b></td>
+ <td> <input name="ip_addr_new" type="text"></td></tr>
+ <tr> <td><br><b>Interface</b></td><td><br>
+ {% for choice in TYPE_CHOICES %}
+ <input type="radio" name="hdwr_type_new2" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}
+ </td></tr>
+ <tr> <td> <b>dhcp</b></td>
+ <td>
+ <input type="checkbox" name="dhcp_new2"></td></tr>
+ <tr> <td> <b>mac_addr</b></td>
+ <td> <input name="mac_addr_new2" type="text"></td></tr>
+ <tr> <td> <b>ip_addr</b></td>
+ <td> <input name="ip_addr_new2" type="text"></td></tr>
+ <tr> <td> <b>comments</b></td>
+ <td> <textarea rows="10" cols="50" name="comments"></textarea></td></tr>
+</table>
+<br>
+<p><input type="submit" value="Submit">
+</form>
+
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dns.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dns.html
new file mode 100644
index 000000000..da179e5a1
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dns.html
@@ -0,0 +1,40 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>dns info for {{ host.hostname }}</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+ <li><a href="/hostbase/{{ host.id }}/" class="sidebar">host info</a></li>
+ <li><a href="/hostbase/{{ host.id }}/edit/" class="sidebar">edit host info</a></li>
+ <li><a href="edit/" class="sidebar">edit dns info</a></li>
+ <li><a href="/hostbase/{{ host.id }}/logs/" class="sidebar">change logs</a></li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+{% for interface in host.interface_set.all %}
+ {% for ip in interface.ip_set.all %}
+ <ul><li> <b>ip_addr:</b> {{ ip.ip_addr }}</li>
+ {% for name in ip.name_set.all %}
+ <ul> <li><b>name:</b> {{ name.name }}</li> <ul>
+ {% for cname in name.cname_set.all %}
+ <li> <b>cname:</b> {{ cname.cname }}</li>
+ {% endfor %}
+ {% for mx in name.mxs.all %}
+ <li> <b>mx:</b> {{ mx.priority }} {{ mx.mx }}</li>
+ {% endfor %}
+ </ul></ul>
+ {% endfor %}
+ </ul>
+ {% endfor %}
+{% endfor %}
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dnsedit.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dnsedit.html
new file mode 100644
index 000000000..b1b71ab67
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/dnsedit.html
@@ -0,0 +1,98 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>dns info for {{ host.hostname }}</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+ <li><a href="/hostbase/{{ host.id }}/" class="sidebar">host info</a></li>
+ <li><a href="/hostbase/{{ host.id }}/edit/" class="sidebar">edit host info</a></li>
+ <li><a href="/hostbase/{{ host.id }}/dns/" class="sidebar">see dns info</a></li>
+ <li><a href="/hostbase/{{ host.id }}/logs/" class="sidebar">change logs</a></li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<form name="dns" action="?sub=true" method="post">
+<input type="hidden" name="host" value="{{ host.id }}">
+<table border="0" width="100%">
+ <colgroup>
+ <col width="150">
+ <col width="*">
+ {% for interface in interfaces %}
+ <tr><td><br></td></tr>
+ <tr> <td> <b>interface type</b> </td>
+ <td> {{ interface.hdwr_type }} </td></tr>
+ <tr> <td> <b>mac_addr</b> </td>
+ <td> {{ interface.mac_addr }} </td></tr>
+ <tr><td><hr></td><td><hr></td></tr>
+ {% for ip in info %}
+ {% ifequal ip.0.interface interface %}
+ <tr> <td> <b>ip_addr</b></td>
+ <td>{{ ip.0.ip_addr }}</td></tr>
+ {% for name in ip.1 %}
+ <tr> <td><b>name(dns)</b></td>
+ <td> <input name="name{{ name.id }}" type="text" value="{{ name.name }}">
+ <select name="dns_view{{ name.id }}">
+ {% for choice in DNS_CHOICES %}
+ {% ifequal name.dns_view choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select>
+ <a style="font-size:75%" href="/hostbase/{{ host.id }}/name/{{ name.id }}/confirm">remove</a></td></tr>
+ {% for cname in cnames %}
+ {% ifequal name cname.name %}
+ <tr> <td> <b>cname</b></td>
+ <td> <input name="cname{{ cname.id }}" type="text" value="{{ cname.cname }}">
+ <a style="font-size:75%" href="/hostbase/{{ host.id }}/cname/{{ cname.id }}/confirm">remove</a></td></tr>
+ {% endifequal %}
+ {% endfor %}
+ <tr> <td> <b>cname</b></td>
+ <td> <input name="{{ name.id }}cname" type="text"></td></tr>
+ {% for mx in mxs %}
+ {% ifequal mx.0 name.id %}
+ {% for record in mx.1 %}
+ <tr> <td> <b>mx</b></td>
+ <td> <input name="priority{{ record.id }}" type="text" size="6" value="{{ record.priority }}">
+ <input name="mx{{ record.id }}" type="text" value="{{ record.mx }}">
+ <a style="font-size:75%" href="/hostbase/{{ host.id }}/mx/{{ record.id }}/{{ name.id }}/confirm">remove</a></td></tr>
+ {% endfor %}
+ {% endifequal %}
+ {% endfor %}
+ <tr> <td> <b>mx</b></td>
+ <td> <input name="{{ name.id }}priority" type="text" size="6">
+ <input name="{{ name.id }}mx" type="text"></td></tr>
+ {% endfor %}
+ <tr> <td> <b>name</b></td>
+ <td> <input name="{{ ip.0.ip_addr }}name" type="text">
+ <select name="{{ ip.0.ip_addr }}dns_view">
+ {% for choice in DNS_CHOICES %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endfor %}
+ </select></td></tr>
+ <tr> <td> <b>cname</b></td>
+ <td> <input name="{{ ip.0.ip_addr }}cname" type="text"></td></tr>
+ <tr> <td> <b>mx</b></td>
+ <td> <input name="{{ ip.0.ip_addr }}priority" type="text" size="6">
+ <input name="{{ ip.0.ip_addr }}mx" type="text"></td></tr>
+ <tr><td></td></tr>
+ <tr><td><hr></td><td><hr></td></tr>
+ {% endifequal %}
+ {% endfor %}
+ {% endfor %}
+ </table>
+
+<p><input type="submit" value="Submit">
+</form>
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/edit.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/edit.html
new file mode 100644
index 000000000..961c9d143
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/edit.html
@@ -0,0 +1,191 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>{{ host.hostname }}</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+<li><a href="/hostbase/{{ host.id }}/" class="sidebar">host info</a></li>
+<li><a href="/hostbase/{{ host.id }}/dns/" class="sidebar">detailed dns info</a></li>
+<li><a href="/hostbase/{{ host.id }}/dns/edit/" class="sidebar">edit dns info</a></li>
+<li><a href="/hostbase/{{ host.id }}/logs/" class="sidebar">change logs</a></li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<script language="JavaScript" type="text/Javascript">
+function toggleAddr(interface_id){
+ if(document.getElementById){
+ var style = document.getElementById('ipaddr'+interface_id).style;
+ style.display = style.display? "":"block";
+ }
+}
+function toggleInter(){
+ if(document.getElementById){
+ var style = document.getElementById('interface').style;
+ style.display = style.display? "":"block";
+ }
+}
+</script>
+
+<style type=text/css>
+{% for interface in interfaces %}
+div#ipaddr{{ interface.0.id }}{
+ display: none;
+}
+{% endfor %}
+div#interface{
+ display: none;
+}
+</style>
+
+<form name="hostdata" action="" method="post">
+<fieldset class="module aligned ()">
+<input type="hidden" name="host" value="{{ host.id }}">
+ <label for="id_hostname">hostname:</label>
+ <input name="hostname" value="{{ host.hostname }}"><br>
+ <label for="id_whatami">whatami:</label>
+ <select name="whatami">
+ {% for choice in host.WHATAMI_CHOICES %}
+ {% ifequal host.whatami choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select><br>
+ <label for="id_netgroup">netgroup:</label>
+ <select name="netgroup">
+ {% for choice in host.NETGROUP_CHOICES %}
+ {% ifequal host.netgroup choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select><br>
+ <label for="id_security_class">class:</label>
+ <select name="security_class">
+ {% for choice in host.CLASS_CHOICES %}
+ {% ifequal host.security_class choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select><br>
+ <label for="id_support">support:</label>
+ <select name="support">
+ {% for choice in host.SUPPORT_CHOICES %}
+ {% ifequal host.support choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select><br>
+ <label for="id_csi">csi:</label>
+ <input name="csi" type="text" value="{{ host.csi }}"><br>
+ <label for="id_printq">printq:</label>
+ <input name="printq" type="text" value="{{ host.printq }}"><br>
+ <label for="id_outbound_smtp">outbound_smtp:</label>
+ {% if host.outbound_smtp %}
+ <input type="checkbox" checked="checked" name="outbound_smtp">
+ {% else %}
+ <input type="checkbox" name="outbound_smtp">
+ {% endif %}<br>
+ <label for="id_primary_user">primary_user:</label>
+ <input name="primary_user" type="text" size="32" value="{{ host.primary_user }}"><br>
+ <label for="id_administrator">administrator:</label>
+ <input name="administrator" type="text" size="32" value="{{ host.administrator }}"><br>
+ <label for="id_location">location:</label>
+ <input name="location" type="text" value="{{ host.location }}"><br>
+ <label for="id_expiration_date">expiration_date:</label>
+ <input name="expiration_date" type="text" value="{{ host.expiration_date }}"> YYYY-MM-DD<br>
+ {% for interface in interfaces %}
+ <label for="id_interface">Interface:</label>
+ <select name="hdwr_type{{ interface.0.id }}">
+ {% for choice in interface.0.TYPE_CHOICES %}
+ {% ifequal interface.0.hdwr_type choice.0 %}
+ <option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+ {% else %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endifequal %}
+ {% endfor %}
+ </select><br>
+ <label for="id_dhcp">dhcp:</label>
+ {% if interface.0.dhcp %}
+ <input type="checkbox" checked="checked" name="dhcp{{ interface.0.id }}">
+ {% else %}
+ <input type="checkbox" name="dhcp{{ interface.0.id }}">
+ {% endif %}<br>
+ <label for="id_mac_addr">mac_addr:</label>
+ <input name="mac_addr{{ interface.0.id }}" type="text" value="{{ interface.0.mac_addr }}">
+ <a style="font-size:75%" href="/hostbase/{{ host.id }}/interface/{{ interface.0.id }}/confirm">remove</a><br>
+ {% for ip in interface.1 %}
+ <label for="id_ip_addr">ip_addr:</label>
+ <input name="ip_addr{{ ip.id }}" type="text" value="{{ ip.ip_addr }}">
+ <a style="font-size:75%" href="/hostbase/{{ host.id }}/ip/{{ ip.id }}/confirm">remove</a><br>
+ {% endfor %}
+
+<!-- Section for adding a new IP address to an existing interface -->
+<!-- By default, section is hidden -->
+ <div id=ipaddr{{ interface.0.id }}>
+ <label for="id_ip_addr">ip_addr:</label>
+ <input name="{{ interface.0.id }}ip_addr" type="text"><br>
+ </div>
+ <a style="font-size:75%" href=# onclick="toggleAddr({{ interface.0.id }})">Add a New IP Address</a><br>
+ {% endfor %}
+<!-- End section for new IP address -->
+
+<!-- Section for add an entirely new interface to a host -->
+<!-- By default, section is hidden -->
+ <div id=interface>
+ <label for="id_interface">Interface:</label>
+ <select name="hdwr_type_new">
+ {% for choice in TYPE_CHOICES %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endfor %}
+ </select><br>
+ <label for="id_dhcp">dhcp:</label>
+ {% if host.dhcp %}
+ <input type="checkbox" checked="checked" name="dhcp_new">
+ {% else %}
+ <input type="checkbox" name="dhcp_new">
+ {% endif %}<br>
+ <label for="id_mac_addr">mac_addr:</label>
+ <td> <input name="mac_addr_new" type="text"><br>
+ <label for="id_ip_addr">ip_addr:</label>
+ <td> <input name="ip_addr_new" type="text"><br>
+</div>
+<a style="font-size:75%" href=# onclick="toggleInter()">Add a New Interface</a><br>
+<!-- End new interface section -->
+
+
+<label for="id_comments">comments:</label>
+<textarea rows="10" cols="50" name="comments">{{ host.comments }}</textarea><br>
+<a style="font-size:75%" href="/hostbase/{{ host.id }}/dns/edit">edit detailed DNS information for this host</a>
+<br>
+this host is
+<select name="status">
+{% for choice in host.STATUS_CHOICES %}
+{% ifequal host.status choice.0 %}
+<option value="{{ choice.0 }}" selected="selected">{{ choice.1 }}
+{% else %}
+<option value="{{ choice.0 }}">{{ choice.1 }}
+{% endifequal %}
+{% endfor %}
+</select><br>
+last update on {{ host.last }}<br>
+<input type="submit" value="submit">
+<input type="reset" value="cancel" onclick="history.back()">
+</form>
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/errors.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/errors.html
new file mode 100644
index 000000000..e5429b86c
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/errors.html
@@ -0,0 +1,31 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Search Results</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+{% if failures %}
+There were errors in the following fields<br><br>
+{% for failure in failures %}
+
+<font color="#FF0000">{{ failure }}</font><br>
+{% comment %}
+{{ failure.1|join:", " }}
+{% endcomment %}
+
+{% endfor %}
+{% endif %}
+<br>
+Press the back button on your browser and edit those field(s)
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/host.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/host.html
new file mode 100644
index 000000000..d6b8873bc
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/host.html
@@ -0,0 +1,80 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>{{ host.hostname }}</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+ <li><a href="dns/" class="sidebar">detailed dns info</a></li>
+ <li><a href="edit/" class="sidebar">edit host info</a></li>
+ <li><a href="dns/edit/" class="sidebar">edit dns info</a></li>
+ <li><a href="logs/" class="sidebar">change logs</a></li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<table border="0" width="100%">
+ <colgroup>
+ <col width="150">
+ <col width="*">
+ <tr> <td> <b>hostname</b></td>
+ <td> {{ host.hostname }}</td></tr>
+ <tr> <td> <b>whatami</b></td>
+ <td> {{ host.whatami }}</td></tr>
+ <tr> <td> <b>netgroup</b></td>
+ <td> {{ host.netgroup }}</td></tr>
+ <tr> <td> <b>class</b></td>
+ <td> {{ host.security_class }}</td></tr>
+ <tr> <td> <b>support</b></td>
+ <td> {{ host.support }}</td></tr>
+ <tr> <td> <b>csi</b></td>
+ <td> {{ host.csi }}</td></tr>
+ <tr> <td> <b>printq</b></td>
+ <td> {{ host.printq }}</td></tr>
+ <tr> <td> <b>outbound_smtp</b></td>
+ {% if host.outbound_smtp %}
+ <td> y </td></tr>
+ {% else %}
+ <td> n </td></tr>
+ {% endif %}
+ <tr> <td> <b>primary_user</b></td>
+ <td> {{ host.primary_user }}</td></tr>
+ <tr> <td> <b>administrator</b></td>
+ <td> {{ host.administrator }}</td></tr>
+ <tr> <td> <b>location</b></td>
+ <td> {{ host.location }}</td></tr>
+ <tr> <td> <b>expiration_date</b></td>
+ <td> {{ host.expiration_date }}</td></tr>
+ {% for interface in host.inserface_set.all %}
+ <tr> <td><br><b>Interface</b></td>
+ {% ifnotequal interface.0.hdwr_type 'no' %}
+ <td><br>{{ interface.0.hdwr_type }}</td></tr>
+ {% endifnotequal %}
+ {% if interface.0.dhcp %}
+ <tr> <td> <b>mac_addr</b></td>
+ <td> {{ interface.0.mac_addr }}</b></td></tr>
+ {% endif %}
+ {% for ip in interface.1 %}
+ <tr> <td> <b>ip_addr</b></td>
+ <td> {{ ip.ip_addr }}</td></tr>
+ {% endfor %}
+ {% endfor %}
+ <tr> <td valign="top"> <b>comments</b></td>
+ <td>
+ {{ host.comments|linebreaksbr }}<br>
+ </td></tr>
+
+</table>
+<a style="font-size:75%" href="/hostbase/{{ host.id }}/dns/">see detailed DNS information for this host</a>
+<br><br>
+this host is {{ host.status }}<br>
+last update on {{ host.last }}<br>
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/host_confirm_delete.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/host_confirm_delete.html
new file mode 100644
index 000000000..b5d794b50
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/host_confirm_delete.html
@@ -0,0 +1,89 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Are you sure you want to remove {{ object.hostname }}?</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+ <li><a href="dns/" class="sidebar">detailed dns info</a></li>
+ <li><a href="edit/" class="sidebar">edit host info</a></li>
+ <li><a href="dns/edit/" class="sidebar">edit dns info</a></li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<table border="0" width="100%">
+ <colgroup>
+ <col width="150">
+ <col width="*">
+ <tr> <td> <b>hostname</b></td>
+ <td> {{ object.hostname }}</td></tr>
+ <tr> <td> <b>whatami</b></td>
+ <td> {{ object.whatami }}</td></tr>
+ <tr> <td> <b>netgroup</b></td>
+ <td> {{ object.netgroup }}</td></tr>
+ <tr> <td> <b>class</b></td>
+ <td> {{ object.security_class }}</td></tr>
+ <tr> <td> <b>support</b></td>
+ <td> {{ object.support }}</td></tr>
+ <tr> <td> <b>csi</b></td>
+ <td> {{ object.csi }}</td></tr>
+ <tr> <td> <b>printq</b></td>
+ <td> {{ object.printq }}</td></tr>
+ <tr> <td> <b>dhcp</b></td>
+ {% if host.dhcp %}
+ <td> y </td></tr>
+ {% else %}
+ <td> n </td></tr>
+ {% endif %}
+ <tr> <td> <b>outbound_smtp</b></td>
+ {% if host.outbound_smtp %}
+ <td> y </td></tr>
+ {% else %}
+ <td> n </td></tr>
+ {% endif %}
+ <tr> <td> <b>primary_user</b></td>
+ <td> {{ object.primary_user }}</td></tr>
+ <tr> <td> <b>administrator</b></td>
+ <td> {{ object.administrator }}</td></tr>
+ <tr> <td> <b>location</b></td>
+ <td> {{ object.location }}</td></tr>
+ <tr> <td> <b>expiration_date</b></td>
+ <td> {{ object.expiration_date }}</td></tr>
+ {% for interface in interfaces %}
+ <tr> <td><br><b>Interface</b></td>
+ {% ifnotequal interface.0.hdwr_type 'no' %}
+ <td><br>{{ interface.0.hdwr_type }}</td></tr>
+ {% endifnotequal %}
+ <tr> <td> <b>mac_addr</b></td>
+ <td> {{ interface.0.mac_addr }}</b></td></tr>
+ {% for ip in interface.1 %}
+ <tr> <td> <b>ip_addr</b></td>
+ <td> {{ ip.ip_addr }}</td></tr>
+ {% endfor %}
+ {% endfor %}
+ <tr> <td valign="top"> <b>comments</b></td>
+ <td>
+ {{ object.comments|linebreaksbr }}<br>
+ </td></tr>
+
+</table>
+<a style="font-size:75%" href="/hostbase/{{ object.id }}/dns/">see detailed DNS information for this host</a>
+<br><br>
+this host is {{ object.status }}<br>
+last update on {{ object.last }}<br>
+
+<form name="input" action="remove.html?sub=true" method="post">
+<input type="submit" value="remove">
+<input type="reset" value="cancel" onclick="history.back()">
+</form>
+
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/log_detail.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/log_detail.html
new file mode 100644
index 000000000..aa9679cbd
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/hostbase/log_detail.html
@@ -0,0 +1,23 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Change Logs for {{ object.hostname }}</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<ul>
+<li><b>Hostname:</b>{{ object.hostname }}</li>
+<li><b>Date:</b>{{ object.date }}</li>
+<li><b>Log:</b>{{ object.log }}</li>
+</ul>
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/index.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/index.html
new file mode 100644
index 000000000..92258b648
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/index.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block pagebanner %}
+ <div class="header">
+ <h2>Welcome to Hostbase!</h2>
+ <p>Hostbase is a web based management tools for Bcfg2 Hosts</p>
+ </div>
+ <br/>
+{% endblock %}
+{% block sidebar %}
+<a href="/login/" class="sidebar">login to hostbase</a><br>
+<a href="/hostbase/" class="sidebar">search for hosts</a><br>
+<a href="hostbase/zones/" class="sidebar">zone file information</a>
+{% endblock %}
+{% block content %}
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/login.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/login.html
new file mode 100644
index 000000000..ec24a0fc0
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/login.html
@@ -0,0 +1,37 @@
+{% extends "base.html" %}
+{% block pagebanner %}
+ <div class="header">
+ <h2>Login to Hostbase!</h2>
+ <p>You must login to manage hosts</p>
+ </div>
+ <br/>
+{% endblock %}
+{% block sidebar %}
+<a href="/hostbase/" class="sidebar">search for hosts</a><br>
+<a href="/hostbase/new" class="sidebar">add a new host</a><br>
+<a href="hostbase/zones/" class="sidebar">zone file information</a>
+{% endblock %}
+{% block content %}
+ {% if form.has_errors %}
+ {{ form.username.errors|join:", " }}
+ <p>Login Failed.</p>
+ {% endif %}
+ {% if user.is_authenticated %}
+ <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
+ {% else %}
+ <p>Welcome, user. Please log in.</p>
+ <form name="input" action="." method="post">
+ <input name="username" type="text">
+ <br />
+ <input name="password" type="password">
+ <br />
+ <input type="submit" value="Login">
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ {% else %}
+ <input type="hidden" name="next" value="/hostbase/" />
+ {% endif %}
+
+ </form>
+ {% endif %}
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.html
new file mode 100644
index 000000000..994f631a8
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.html
@@ -0,0 +1,13 @@
+{% extends "base.html" %}
+{% block pagebanner %}
+ <div class="header">
+ <h2>You are logged out of Hostbase!</h2>
+ </div>
+ <br/>
+{% endblock %}
+{% block sidebar %}
+<a href="/login/" class="sidebar">Login to Hostbase</a>
+{% endblock %}
+{% block content %}
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.tmpl b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.tmpl
new file mode 100644
index 000000000..e71e90e76
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logout.tmpl
@@ -0,0 +1,6 @@
+<p>
+{% if logged_in %}
+<a href="/logout/" class="sidebar">logout</a>
+{% else %}
+<a href="/login/" class="sidebar">login</a>
+{% endif %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logviewer.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logviewer.html
new file mode 100644
index 000000000..806ccd63d
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/logviewer.html
@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Change Logs for {{ hostname }}</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+{% if host.get_logs %}
+<ul>
+{% for log in host.get_logs %}
+<li><a href="{{ log.id }}/">{{ log.date }}</li>
+{% endfor %}
+</ul>
+{% else %}
+There are no logs for this host<br>
+{% endif %}
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/navbar.tmpl b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/navbar.tmpl
new file mode 100644
index 000000000..877d427d0
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/navbar.tmpl
@@ -0,0 +1,5 @@
+<a href="/hostbase/" class="sidebar">host search</a><br>
+<a href="/hostbase/new" class="sidebar">add a new host</a><br>
+<a href="/hostbase/zones" class="sidebar">zone file information</a><br>
+<a href="/hostbase/zones/new" class="sidebar">add a zone</a><br>
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/new.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/new.html
new file mode 100644
index 000000000..2dcd6271f
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/new.html
@@ -0,0 +1,102 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>new host information</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+<a href="/hostbase/" class="sidebar">search hostbase</a>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<form name="hostdata" action="?sub=true" method="post">
+<input type="hidden" name="host">
+<table border="0" width="100%">
+ <colgroup>
+ <col width="150">
+ <col width="*">
+ <tr> <td> <b>hostname</b></td>
+ <td> <input name="hostname" type="text" ></td></tr>
+ <tr> <td> <b>whatami</b></td>
+ <td>
+ <select name="whatami">
+ {% for choice in WHATAMI_CHOICES %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endfor %}
+ </select>
+ </td></tr>
+ <tr> <td> <b>netgroup</b></td>
+ <td>
+ <select name="netgroup">
+ {% for choice in NETGROUP_CHOICES %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endfor %}
+ </select>
+ </td></tr>
+ <tr> <td> <b>class</b></td>
+ <td>
+ <select name="security_class">
+ {% for choice in CLASS_CHOICES %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endfor %}
+ </select></td></tr>
+ <tr> <td> <b>support</b></td>
+ <td>
+ <select name="support">
+ {% for choice in SUPPORT_CHOICES %}
+ <option value="{{ choice.0 }}">{{ choice.1 }}
+ {% endfor %}
+ </select></td></tr>
+ <tr> <td> <b>csi</b></td>
+ <td> <input name="csi" type="text" ></td></tr>
+ <tr> <td> <b>printq</b></td>
+ <td> <input name="printq" type="text" ></td></tr>
+ <tr> <td> <b>outbound_smtp</b></td>
+ <td>
+ <input type="checkbox" name="outbound_smtp"></td></tr>
+ <tr> <td> <b>primary_user</b></td>
+ <td> <input name="primary_user" type="text" size="32" > (email address)</td></tr>
+ <tr> <td> <b>administrator</b></td>
+ <td> <input name="administrator" type="text" size="32" > (email address)</td></tr>
+ <tr> <td> <b>location</b></td>
+ <td> <input name="location" type="text" ></td></tr>
+ <tr> <td> <b>expiration_date</b></td>
+ <td> <input name="expiration_date" type="text" size="10" >YYYY-MM-DD</td></tr>
+ <tr> <td><br><b>Interface</b></td><td><br>
+ {% for choice in TYPE_CHOICES %}
+ <input type="radio" name="hdwr_type_new" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}
+ </td></tr>
+ <tr> <td> <b>dhcp</b></td>
+ <td>
+ <input type="checkbox" name="dhcp_new"></td></tr>
+ <tr> <td> <b>mac_addr</b></td>
+ <td> <input name="mac_addr_new" type="text"></td></tr>
+ <tr> <td> <b>ip_addr</b></td>
+ <td> <input name="ip_addr_new" type="text"></td></tr>
+ <tr> <td><br><b>Interface</b></td><td><br>
+ {% for choice in TYPE_CHOICES %}
+ <input type="radio" name="hdwr_type_new2" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}
+ </td></tr>
+ <tr> <td> <b>dhcp</b></td>
+ <td>
+ <input type="checkbox" name="dhcp_new2"></td></tr>
+ <tr> <td> <b>mac_addr</b></td>
+ <td> <input name="mac_addr_new2" type="text"></td></tr>
+ <tr> <td> <b>ip_addr</b></td>
+ <td> <input name="ip_addr_new2" type="text"></td></tr>
+ <tr> <td> <b>comments</b></td>
+ <td> <textarea rows="10" cols="50" name="comments"></textarea></td></tr>
+</table>
+<br>
+<p><input type="submit" value="Submit">
+</form>
+
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/remove.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/remove.html
new file mode 100644
index 000000000..4329200dd
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/remove.html
@@ -0,0 +1,89 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Are you sure you want to remove {{ host.hostname }}?</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+ <li><a href="dns/" class="sidebar">detailed dns info</a></li>
+ <li><a href="edit/" class="sidebar">edit host info</a></li>
+ <li><a href="dns/edit/" class="sidebar">edit dns info</a></li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<table border="0" width="100%">
+ <colgroup>
+ <col width="150">
+ <col width="*">
+ <tr> <td> <b>hostname</b></td>
+ <td> {{ host.hostname }}</td></tr>
+ <tr> <td> <b>whatami</b></td>
+ <td> {{ host.whatami }}</td></tr>
+ <tr> <td> <b>netgroup</b></td>
+ <td> {{ host.netgroup }}</td></tr>
+ <tr> <td> <b>class</b></td>
+ <td> {{ host.security_class }}</td></tr>
+ <tr> <td> <b>support</b></td>
+ <td> {{ host.support }}</td></tr>
+ <tr> <td> <b>csi</b></td>
+ <td> {{ host.csi }}</td></tr>
+ <tr> <td> <b>printq</b></td>
+ <td> {{ host.printq }}</td></tr>
+ <tr> <td> <b>dhcp</b></td>
+ {% if host.dhcp %}
+ <td> y </td></tr>
+ {% else %}
+ <td> n </td></tr>
+ {% endif %}
+ <tr> <td> <b>outbound_smtp</b></td>
+ {% if host.outbound_smtp %}
+ <td> y </td></tr>
+ {% else %}
+ <td> n </td></tr>
+ {% endif %}
+ <tr> <td> <b>primary_user</b></td>
+ <td> {{ host.primary_user }}</td></tr>
+ <tr> <td> <b>administrator</b></td>
+ <td> {{ host.administrator }}</td></tr>
+ <tr> <td> <b>location</b></td>
+ <td> {{ host.location }}</td></tr>
+ <tr> <td> <b>expiration_date</b></td>
+ <td> {{ host.expiration_date }}</td></tr>
+ {% for interface in interfaces %}
+ <tr> <td><br><b>Interface</b></td>
+ {% ifnotequal interface.0.hdwr_type 'no' %}
+ <td><br>{{ interface.0.hdwr_type }}</td></tr>
+ {% endifnotequal %}
+ <tr> <td> <b>mac_addr</b></td>
+ <td> {{ interface.0.mac_addr }}</b></td></tr>
+ {% for ip in interface.1 %}
+ <tr> <td> <b>ip_addr</b></td>
+ <td> {{ ip.ip_addr }}</td></tr>
+ {% endfor %}
+ {% endfor %}
+ <tr> <td valign="top"> <b>comments</b></td>
+ <td>
+ {{ host.comments|linebreaksbr }}<br>
+ </td></tr>
+
+</table>
+<a style="font-size:75%" href="/hostbase/{{ host.id }}/dns/">see detailed DNS information for this host</a>
+<br><br>
+this host is {{ host.status }}<br>
+last update on {{ host.last }}<br>
+
+<form name="input" action="remove.html?sub=true" method="post">
+<input type="submit" value="remove">
+<input type="reset" value="cancel" onclick="history.back()">
+</form>
+
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/results.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/results.html
new file mode 100644
index 000000000..45b22058d
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/results.html
@@ -0,0 +1,45 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Search Results</h2>
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+{% if hosts %}
+<table border="0" width="100%">
+ <colgroup>
+ <col width="200">
+ <col width="75">
+ <col width="50">
+ <col width="50">
+ <col width="50">
+ <col width="*">
+ <tr> <td><b>hostname</b></td>
+ <td> <b>status</b> </td>
+ </tr>
+ {% for host in hosts %}
+ <tr> <td>{{ host.0 }}</td>
+ <td> {{ host.2 }} </td>
+ <td> <a href="{{ host.1 }}">view</a> </td>
+ <td> <a href="{{ host.1 }}/edit">edit</a> </td>
+ <td> <a href="{{ host.1 }}/copy">copy</a> </td>
+ <td> <a href="{{ host.1 }}/logs">logs</a> </td>
+<!-- <td> <a href="{{ host.1 }}/remove">remove</a> </td> -->
+ </tr>
+ {% endfor %}
+</table>
+{% else %}
+No hosts matched your query<br>
+Click the back button on your browser to edit your search
+{% endif %}
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/search.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/search.html
new file mode 100644
index 000000000..409d418fe
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/search.html
@@ -0,0 +1,57 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Welcome to Hostbase!</h2>
+ <p>search for hosts using one or more of the fields below
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+<a href="/hostbase/new" class="sidebar">add a new host</a><br>
+<a href="/hostbase/zones" class="sidebar">zone file information</a><br>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+{% comment %}
+ ...or go to <a href="hostinfo">this</a>
+ page to enter hostinfo-like queries<br><br>
+{% endcomment %}
+
+<form name="input" action="?sub=true" method="post">
+ <fieldset class="module aligned ()">
+ <label for="hostname">hostname:</label><input name="hostname" type="text" ><br>
+ <label for="netgroup">netgroup:</label><input name="netgroup" type="text" ><br>
+ <label for="security_class">class:</label><input name="security_class" type="text" ><br>
+ <label for="support">support:</label><input name="support" type="text" ><br>
+ <label for="csi">csi:</label><input name="csi" type="text" ><br>
+ <label for="printq">printq:</label><input name="printq" type="text" ><br>
+ <label for="outbound_smtp">outbound_smtp:</label>
+ {% for choice in yesno %}
+ <input type="radio" name="outbound_smtp" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}<br>
+ <label for="primary_user">primary_user:</label><input name="primary_user" type="text" ><br>
+ <label for="administrator">administrator:</label><input name="administrator" type="text" ><br>
+ <label for="location">location:</label><input name="location" type="text" ><br>
+ <label for="expiration_date">expiration_date:</label><input name="expiration_date" type="text" ><br>
+ <br><label for="Interface">Interface:</label>
+ {% for choice in TYPE_CHOICES %}
+ <input type="radio" name="hdwr_type" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}<br>
+ <label for="dhcp">dhcp:</label>
+ {% for choice in yesno %}
+ <input type="radio" name="dhcp" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}<br>
+ <label for="mac_addr">mac_addr:</label><input name="mac_addr" type="text" ><br>
+ <label for="ip_addr">ip_addr:</label><input name="ip_addr" type="text" ><br>
+ <label for="dns_view">dns_viewer:</label>
+ {% for choice in DNS_CHOICES %}
+ <input type="radio" name="dns_view" value="{{ choice.0 }}" >{{ choice.1 }}
+ {% endfor %}<br>
+ <label for="mx">mx:</label><input name="mx" type="text" ><br>
+<p>
+<input type="submit" value="Search">
+</form>
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneedit.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneedit.html
new file mode 100644
index 000000000..ee355ee87
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneedit.html
@@ -0,0 +1,81 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Zones</h2>
+ <p>Edit information for {{ zone }}
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul>
+<li><a href="/hostbase/zones/{{ zone_id }}/" class="sidebar">view zone</a><br>
+</li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+
+<script language="JavaScript" type="text/Javascript">
+function toggleField(fieldname){
+ if(document.getElementById){
+ var style = document.getElementById(fieldname).style;
+ style.display = style.display? "":"block";
+ }
+}
+</script>
+
+<style type=text/css>
+div#nameserver{
+ display: none;
+}
+div#mx{
+ display: none;
+}
+div#address{
+ display: none;
+}
+</style>
+
+<form name="zonedata" action="" method="post">
+ <fieldset class="module aligned ()">
+<label for="id_zone">zone:</label></td> <td>{{ form.zone }}<br>
+<label for="id_admin">admin:</label></td> <td>{{ form.admin }}<br>
+<label for="id_primary_master">primary_master:</label></td> <td>{{ form.primary_master }}<br>
+<label for="id_expire">expire:</label></td> <td>{{ form.expire }}<br>
+<label for="id_retry">retry:</label></td> <td>{{ form.retry }}<br>
+<label for="id_refresh">refresh:</label></td> <td>{{ form.refresh }}<br>
+<label for="id_ttl">ttl:</label></td> <td>{{ form.ttl }}<br>
+{% for ns in nsforms %}
+<label for="id_name">nameserver:</label></td> <td>{{ ns.name }}<br>
+{% endfor %}
+</table>
+<div id=nameserver>
+ <label for="id_name">nameserver:</label></td> <td>{{ nsadd.name }}<br>
+ <label for="id_name">nameserver:</label></td> <td>{{ nsadd.name }}<br>
+</div>
+<a style="font-size:75%" href=# onclick="toggleField('nameserver')">Add NS records</a><br>
+{% for mx in mxforms %}
+<label for="id_mx">mx:</label></td> <td>{{ mx.priority }} {{ mx.mx }}<br>
+{% endfor %}
+<div id=mx>
+ <label for="id_mx">mx:</label></td> <td>{{ mxadd.priority }} {{ mxadd.mx }}<br>
+ <label for="id_mx">mx:</label></td> <td>{{ mxadd.priority }} {{ mxadd.mx }}<br>
+</div>
+<a style="font-size:75%" href=# onclick="toggleField('mx')">Add MX records</a><br>
+{% for a in aforms %}
+<label for="id_address">ip address:</label></td> <td>{{ a.ip_addr }}<br>
+{% endfor %}
+<div id=address>
+ <label for="id_address">ip address:</label></td> <td>{{ addadd.ip_addr }}<br>
+ <label for="id_address">ip address:</label></td> <td>{{ addadd.ip_addr }}<br>
+</div>
+<a style="font-size:75%" href=# onclick="toggleField('address')">Add A records</a><br>
+<label for="id_aux">aux:</label></td> <td>{{ form.aux }}<br>
+<p><input type="submit" value="Submit">
+</form>
+
+{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zonenew.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zonenew.html
new file mode 100644
index 000000000..b59fa9e3c
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zonenew.html
@@ -0,0 +1,43 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Zones</h2>
+ <p>Enter information for a new zone to be generated by Hostbase
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+<form name="zonedata" action="" method="post">
+ <fieldset class="module aligned ()">
+ {{ form.as_p}}
+<!--
+ <label for="id_zone">zone:</label>{{ form.zone }}<br>
+ <label for="id_admin">admin:</label>{{ form.admin }}<br>
+ <label for="id_primary_master">primary_master:</label>{{ form.primary_master }}<br>
+ <label for="id_expire">expire:</label>{{ form.expire }}<br>
+ <label for="id_retry">retry:</label>{{ form.retry }}<br>
+ <label for="id_refresh">refresh:</label>{{ form.refresh }}<br>
+ <label for="id_ttl">ttl:</label>{{ form.ttl }}<br>
+ <label for="id_name">nameserver:</label>{{ nsform.name }}<br>
+ <label for="id_name">nameserver:</label>{{ nsform.name }}<br>
+ <label for="id_name">nameserver:</label>{{ nsform.name }}<br>
+ <label for="id_name">nameserver:</label>{{ nsform.name }}<br>
+ <label for="id_mx">mx:</label>{{ mxform.priority }} {{ mxform.mx }}<br>
+ <label for="id_mx">mx:</label>{{ mxform.priority }} {{ mxform.mx }}<br>
+ <label for="id_mx">ip address:</label>{{ aform.ip_addr }}<br>
+ <label for="id_mx">ip address:</label>{{ aform.ip_addr }}<br>
+ <label for="id_aux">aux:
+(information not generated from Hostbase)</label>{{ form.aux }}<br>
+--!>
+ <p><input type="submit" value="Submit">
+ </fieldset>
+</form>
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zones.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zones.html
new file mode 100644
index 000000000..c773e7922
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zones.html
@@ -0,0 +1,37 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Zones</h2>
+ <p>Hostbase generates DNS zone files for the following zones.
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+{% if zone_list %}
+<table border="0" width="100%">
+ <colgroup>
+ <col width="200">
+ <col width="75">
+ <col width="50">
+ <col width="*">
+ <tr> <td><b>zone</b></td>
+ </tr>
+ {% for zone in zone_list|dictsort:"zone" %}
+ <tr> <td> {{ zone.zone }}</td>
+ <td> <a href="{{ zone.id }}">view</a> </td>
+ <td> <a href="{{ zone.id }}/edit">edit</a> </td>
+ </tr>
+ {% endfor %}
+</table>
+{% else %}
+There is no zone data currently in the database<br>
+{% endif %}
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneview.html b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneview.html
new file mode 100644
index 000000000..fa12e3ec5
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/hostbase/webtemplates/zoneview.html
@@ -0,0 +1,71 @@
+{% extends "base.html" %}
+
+{% block pagebanner %}
+ <div class="header">
+ <h2>Zones</h2>
+ <p>Hostbase generates DNS zone files for the following zones.
+ </div>
+ <br/>
+{% endblock %}
+
+{% block sidebar %}
+{% include "navbar.tmpl" %}
+<ul class="sidebar">
+<li><a href="/hostbase/zones/{{ zone.id }}/edit/" class="sidebar">edit zone</a><br>
+</li>
+</ul>
+{% include "logout.tmpl" %}
+{% endblock %}
+
+{% block content %}
+<table border="0" width="100%">
+ <colgroup>
+ <col width="200">
+ <col width="*">
+ <tr> <td> <b>zone</b></td>
+ <td> {{ zone.zone }}</td></tr>
+ <tr> <td> <b>serial</b></td>
+ <td> {{ zone.serial }}</td></tr>
+ <tr> <td> <b>admin</b></td>
+ <td> {{ zone.admin }}</td></tr>
+ <tr> <td> <b>primary_master</b></td>
+ <td> {{ zone.primary_master }}</td></tr>
+ <tr> <td> <b>expire</b></td>
+ <td> {{ zone.expire }}</td></tr>
+ <tr> <td> <b>retry</b></td>
+ <td> {{ zone.retry }}</td></tr>
+ <tr> <td> <b>refresh</b></td>
+ <td> {{ zone.refresh }}</td></tr>
+ <tr> <td> <b>ttl</b></td>
+ <td> {{ zone.ttl }}</td></tr>
+
+ <tr><td valign="top"> <b>nameservers</b></td>
+ <td>
+ {% for nameserver in zone.nameservers.all %}
+ {{ nameserver.name }}<br>
+ {% endfor %}
+ </td></tr>
+ <tr><td valign="top"> <b>mxs</b></td>
+ <td>
+ {% for mx in zone.mxs.all %}
+ {{ mx.priority }} {{ mx.mx }}<br>
+ {% endfor %}
+ </td></tr>
+ {% if addresses %}
+ <tr><td valign="top"> <b>A records</b></td>
+ <td>
+ {% for address in sof.addresses.all %}
+ {{ address.ip_addr }}<br>
+ {% endfor %}
+ </td></tr>
+ {% endif %}
+
+ <tr> <td valign="top"> <b>aux</b></td>
+ <td>
+ {{ zone.aux|linebreaksbr }}
+ </td></tr>
+
+</table>
+<br><br>
+{% endblock %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/ldapauth.py b/src/lib/Bcfg2/Server/Hostbase/ldapauth.py
new file mode 100644
index 000000000..f3db26f67
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/ldapauth.py
@@ -0,0 +1,180 @@
+"""
+Checks with LDAP (ActiveDirectory) to see if the current user is an LDAP(AD)
+user, and returns a subset of the user's profile that is needed by Argonne/CIS
+to set user level privleges in Django
+"""
+
+import os
+import ldap
+
+
+class LDAPAUTHError(Exception):
+ """LDAPAUTHError is raised when somehting goes boom."""
+ pass
+
+
+class ldapauth(object):
+ group_test = False
+ check_member_of = os.environ['LDAP_CHECK_MBR_OF_GRP']
+ securitylevel = 0
+ distinguishedName = None
+ sAMAccountName = None
+ telephoneNumber = None
+ title = None
+ memberOf = None
+ department = None # this will be a list
+ mail = None
+ extensionAttribute1 = None # badgenumber
+ badge_no = None
+
+ def __init__(self, login, passwd):
+ """get username (if using ldap as auth the
+ apache env var REMOTE_USER should be used)
+ from username get user profile from AD/LDAP
+ """
+ #p = self.user_profile(login,passwd)
+ d = self.user_dn(login) # success, distname
+ print(d[1])
+ if d[0] == 'success':
+ pass
+ p = self.user_bind(d[1], passwd)
+ if p[0] == 'success':
+ #parse results
+ parsed = self.parse_results(p[2])
+ print(self.department)
+ self.group_test = self.member_of()
+ securitylevel = self.security_level()
+ print("ACCESS LEVEL: " + str(securitylevel))
+ else:
+ raise LDAPAUTHError(p[2])
+ else:
+ raise LDAPAUTHError(p[2])
+
+ def user_profile(self, login, passwd=None):
+ """NOT USED RIGHT NOW"""
+ ldap_login = "CN=%s" % login
+ svc_acct = os.environ['LDAP_SVC_ACCT_NAME']
+ svc_pass = os.environ['LDAP_SVC_ACCT_PASS']
+ #svc_acct = 'CN=%s,DC=anl,DC=gov' % login
+ #svc_pass = passwd
+
+ search_pth = os.environ['LDAP_SEARCH_PTH']
+
+ try:
+ conn = ldap.initialize(os.environ['LDAP_URI'])
+ conn.bind(svc_acct, svc_pass, ldap.AUTH_SIMPLE)
+ result_id = conn.search(search_pth,
+ ldap.SCOPE_SUBTREE,
+ ldap_login,
+ None)
+ result_type, result_data = conn.result(result_id, 0)
+ return ('success', 'User profile found', result_data,)
+ except ldap.LDAPError:
+ e = sys.exc_info()[1]
+ #connection failed
+ return ('error', 'LDAP connect failed', e,)
+
+ def user_bind(self, distinguishedName, passwd):
+ """Binds to LDAP Server"""
+ search_pth = os.environ['LDAP_SEARCH_PTH']
+ try:
+ conn = ldap.initialize(os.environ['LDAP_URI'])
+ conn.bind(distinguishedName, passwd, ldap.AUTH_SIMPLE)
+ cn = distinguishedName.split(",")
+ result_id = conn.search(search_pth,
+ ldap.SCOPE_SUBTREE,
+ cn[0],
+ None)
+ result_type, result_data = conn.result(result_id, 0)
+ return ('success', 'User profile found', result_data,)
+ except ldap.LDAPError:
+ e = sys.exc_info()[1]
+ #connection failed
+ return ('error', 'LDAP connect failed', e,)
+
+ def user_dn(self, cn):
+ """Uses Service Account to get distinguishedName"""
+ ldap_login = "CN=%s" % cn
+ svc_acct = os.environ['LDAP_SVC_ACCT_NAME']
+ svc_pass = os.environ['LDAP_SVC_ACCT_PASS']
+ search_pth = os.environ['LDAP_SEARCH_PTH']
+
+ try:
+ conn = ldap.initialize(os.environ['LDAP_URI'])
+ conn.bind(svc_acct, svc_pass, ldap.AUTH_SIMPLE)
+ result_id = conn.search(search_pth,
+ ldap.SCOPE_SUBTREE,
+ ldap_login,
+ None)
+ result_type, result_data = conn.result(result_id, 0)
+ raw_obj = result_data[0][1]
+ distinguishedName = raw_obj['distinguishedName']
+ return ('success', distinguishedName[0],)
+ except ldap.LDAPError:
+ e = sys.exc_info()[1]
+ #connection failed
+ return ('error', 'LDAP connect failed', e,)
+
+ def parse_results(self, user_obj):
+ """Clean up the huge ugly object handed to us in the LDAP query"""
+ #user_obj is a list formatted like this:
+ #[('LDAP_DN',{user_dict},),]
+ try:
+ raw_obj = user_obj[0][1]
+ self.memberOf = raw_obj['memberOf']
+ self.sAMAccountName = raw_obj['sAMAccountName'][0]
+ self.distinguishedName = raw_obj['distinguishedName'][0]
+ self.telephoneNumber = raw_obj['telephoneNumber'][0]
+ self.title = raw_obj['title'][0]
+ self.department = raw_obj['department'][0]
+ self.mail = raw_obj['mail'][0]
+ self.badge_no = raw_obj['extensionAttribute1'][0]
+ self.email = raw_obj['extensionAttribute2'][0]
+ display_name = raw_obj['displayName'][0].split(",")
+ self.name_f = raw_obj['givenName'][0]
+ self.name_l = display_name[0]
+ self.is_staff = False
+ self.is_superuser = False
+
+ return
+ except KeyError:
+ e = sys.exc_info()[1]
+ raise LDAPAUTHError("Portions of the LDAP User profile not present")
+
+ def member_of(self):
+ """See if this user is in our group that is allowed to login"""
+ m = [g for g in self.memberOf if g == self.check_member_of]
+ #print m
+ if len(m) == 1:
+ return True
+ else:
+ return False
+
+ def security_level(self):
+ level = self.securitylevel
+
+ user = os.environ['LDAP_GROUP_USER']
+ m = [g for g in self.memberOf if g == user]
+ if len(m) == 1:
+ if level < 1:
+ level = 1
+
+ cspr = os.environ['LDAP_GROUP_SECURITY_LOW']
+ m = [g for g in self.memberOf if g == cspr]
+ if len(m) == 1:
+ if level < 2:
+ level = 2
+
+ cspo = os.environ['LDAP_GROUP_SECURITY_HIGH']
+ m = [g for g in self.memberOf if g == cspo]
+ if len(m) == 1:
+ if level < 3:
+ level = 3
+
+ admin = os.environ['LDAP_GROUP_ADMIN']
+ m = [g for g in self.memberOf if g == admin]
+ if len(m) == 1:
+ if level < 4:
+ level = 4
+
+ return level
diff --git a/src/lib/Bcfg2/Server/Hostbase/manage.py b/src/lib/Bcfg2/Server/Hostbase/manage.py
new file mode 100755
index 000000000..5e78ea979
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/manage.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+ import 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(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ execute_manager(settings)
diff --git a/src/lib/Bcfg2/Server/Hostbase/media/base.css b/src/lib/Bcfg2/Server/Hostbase/media/base.css
new file mode 100644
index 000000000..ddbf02165
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/media/base.css
@@ -0,0 +1,5 @@
+
+/* Import other styles */
+@import url('global.css');
+@import url('layout.css');
+@import url('boxypastel.css');
diff --git a/src/lib/Bcfg2/Server/Hostbase/media/boxypastel.css b/src/lib/Bcfg2/Server/Hostbase/media/boxypastel.css
new file mode 100644
index 000000000..7ae0684ef
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/media/boxypastel.css
@@ -0,0 +1,179 @@
+body {
+ background-color: #fff;
+ color: #000;
+ font: 12px 'Lucida Grande', Arial, Helvetica, sans-serif;
+ margin-left:0px;
+ margin-right:100px;
+}
+/* links */
+a:link {
+ color: #00f;
+ text-decoration: none;
+}
+a:visited {
+ color: #00a;
+ text-decoration: none;
+}
+a:hover {
+ color: #00a;
+ text-decoration: underline;
+}
+a:active {
+ color: #00a;
+ text-decoration: underline;
+}
+/* divs*/
+div.bad {
+ border: 1px solid #660000;
+ background: #FF6A6A;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.modified {
+ border: 1px solid #CC9900;
+ background: #FFEC8B;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.clean {
+ border: 1px solid #006600;
+ background: #9AFF9A;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.extra {
+ border: 1px solid #006600;
+ background: #6699CC;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.warning {
+ border: 1px
+ solid #CC3300;
+ background: #FF9933;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.all-warning {
+ border: 1px solid #DD5544;
+ background: #FFD9A2;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.down {
+ border: 1px
+ solid #999;
+ background-color: #DDD;
+ margin: 10px 0;
+ padding: 8px;
+ text-align: left;
+ margin-left:50px;
+ margin-right:50px;
+}
+div.items{
+ display: none;
+}
+div.nodebox {
+ border: 1px solid #c7cfd5;
+ background: #f1f5f9;
+ margin: 20px 0;
+ padding: 8px 8px 16px 8px;
+ text-align: left;
+ position:relative;
+}
+div.header {
+ background-color: #DDD;
+ padding: 8px;
+ text-indent:50px;
+ position:relative;
+}
+
+/*Spans*/
+.nodename {
+ font-style: italic;
+}
+.nodelisttitle {
+ font-size: 14px;
+}
+
+h2{
+ font-size: 16px;
+ color: #000;
+}
+
+ul.plain {
+ list-style-type:none;
+ text-align: left;
+}
+
+.notebox {
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ padding: 1px;
+ text-indent:0px;
+ border: 1px solid #FFF;
+ background: #999;
+ color: #FFF;
+}
+
+.configbox {
+ position: absolute;
+ bottom: 0px;
+ right: 0px;
+ padding: 1px;
+ text-indent:0px;
+ border: 1px solid #999;
+ background: #FFF;
+ color: #999;
+}
+
+p.indented{
+ text-indent: 50px
+}
+
+/*
+ Sortable tables */
+table.sortable a.sortheader {
+ background-color:#dfd;
+ font-weight: bold;
+ text-decoration: none;
+ display: block;
+}
+table.sortable {
+ padding: 2px 4px 2px 4px;
+ border: 1px solid #000000;
+ border-spacing: 0px
+}
+td.sortable{
+ padding: 2px 8px 2px 8px;
+}
+
+th.sortable{
+ background-color:#F3DD91;
+ border: 1px solid #FFFFFF;
+}
+tr.tablelist {
+ background-color:#EDF3FE;
+}
+tr.tablelist-alt{
+ background-color:#FFFFFF;
+}
diff --git a/src/lib/Bcfg2/Server/Hostbase/media/global.css b/src/lib/Bcfg2/Server/Hostbase/media/global.css
new file mode 100644
index 000000000..73451e1bc
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/media/global.css
@@ -0,0 +1,8 @@
+body {
+ margin:0;
+ padding:0;
+ font-size:12px;
+ font-family:"Lucida Grande","Bitstream Vera Sans",Verdana,Arial,sans-serif;
+ color:#000;
+ background:#fff;
+ }
diff --git a/src/lib/Bcfg2/Server/Hostbase/media/layout.css b/src/lib/Bcfg2/Server/Hostbase/media/layout.css
new file mode 100644
index 000000000..9085cc220
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/media/layout.css
@@ -0,0 +1,62 @@
+/* Page Structure */
+#container { position:absolute; top: 3em; margin-left:1em; margin-right:2em; padding:0; margin-top:1.5em; min-width:
+ 650px; }
+#header { width:100%; }
+#content-main { float:left; }
+
+/* HEADER */
+#header {
+background:#000;
+color:#ffc;
+position:absolute;
+}
+#header a:link, #header a:visited { color:white; }
+#header a:hover { text-decoration:underline; }
+#branding h1 { padding:0 10px; font-size:18px; margin:8px 0; font-weight:normal; color:#f4f379; }
+#branding h2 { padding:0 10px; font-size:14px; margin:-8px 0 8px 0; font-weight:normal; color:#ffc; }
+#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; }
+
+/*SIDEBAR*/
+#sidebar {
+ float:left;
+ position: relative;
+ width: auto;
+ height: 100%;
+ margin-top: 3em;
+ padding-right: 1.5em;
+ padding-left: 1.5em;
+ padding-top: 1em;
+ padding-bottom:3em;
+ background: #000;
+ color:ffc;
+}
+
+a.sidebar:link {color: #fff;}
+a.sidebar:active {color: #fff;}
+a.sidebar:visited {color: #fff;}
+a.sidebar:hover {color: #fff;}
+
+ul.sidebar {
+ color: #ffc;
+ text-decoration: none;
+ list-style-type: none;
+ text-indent: -1em;
+}
+ul.sidebar-level2 {
+ text-indent: -2em;
+ list-style-type: none;
+ font-size: 11px;
+}
+
+/* ALIGNED FIELDSETS */
+.aligned label { display:block; padding:0 1em 3px 0; float:left; width:8em; }
+.aligned label.inline { display:inline; float:none; }
+.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { width:350px; }
+form .aligned p, form .aligned ul { margin-left:7em; padding-left:30px; }
+form .aligned table p { margin-left:0; padding-left:0; }
+form .aligned p.help { padding-left:38px; }
+.aligned .vCheckboxLabel { float:none !important; display:inline; padding-left:4px; }
+.colM .aligned .vLargeTextField, colM .aligned .vXMLLargeTextField { width:610px; }
+.checkbox-row p.help { margin-left:0; padding-left:0 !important; }
+
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/nisauth.py b/src/lib/Bcfg2/Server/Hostbase/nisauth.py
new file mode 100644
index 000000000..ae4c6c021
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/nisauth.py
@@ -0,0 +1,40 @@
+"""Checks with NIS to see if the current user is in the support group"""
+import os
+import crypt, nis
+from Bcfg2.Server.Hostbase.settings import AUTHORIZED_GROUP
+
+
+class NISAUTHError(Exception):
+ """NISAUTHError is raised when somehting goes boom."""
+ pass
+
+class nisauth(object):
+ group_test = False
+# check_member_of = os.environ['LDAP_CHECK_MBR_OF_GRP']
+ samAcctName = None
+ distinguishedName = None
+ sAMAccountName = None
+ telephoneNumber = None
+ title = None
+ memberOf = None
+ department = None #this will be a list
+ mail = None
+ extensionAttribute1 = None #badgenumber
+ badge_no = None
+ uid = None
+
+ def __init__(self,login,passwd=None):
+ """get user profile from NIS"""
+ try:
+ p = nis.match(login, 'passwd.byname').split(":")
+ except:
+ raise NISAUTHError('username')
+ # check user password using crypt and 2 character salt from passwd file
+ if p[1] == crypt.crypt(passwd, p[1][:2]):
+ # check to see if user is in valid support groups
+ # will have to include these groups in a settings file eventually
+ if not login in nis.match(AUTHORIZED_GROUP, 'group.byname').split(':')[-1].split(',') and p[3] != nis.match(AUTHORIZED_GROUP, 'group.byname').split(':')[2]:
+ raise NISAUTHError('group')
+ self.uid = p[2]
+ else:
+ raise NISAUTHError('password')
diff --git a/src/lib/Bcfg2/Server/Hostbase/regex.py b/src/lib/Bcfg2/Server/Hostbase/regex.py
new file mode 100644
index 000000000..41cc0f6f0
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/regex.py
@@ -0,0 +1,6 @@
+import re
+
+date = re.compile('^[0-9]{4}-[0-9]{2}-[0-9]{2}$')
+host = re.compile('^[a-z0-9-_]+(\.[a-z0-9-_]+)+$')
+macaddr = re.compile('^[0-9abcdefABCDEF]{2}(:[0-9abcdefABCDEF]{2}){5}$|virtual')
+ipaddr = re.compile('^[0-9]{1,3}(\.[0-9]{1,3}){3}$')
diff --git a/src/lib/Bcfg2/Server/Hostbase/settings.py b/src/lib/Bcfg2/Server/Hostbase/settings.py
new file mode 100644
index 000000000..4e641f13c
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/settings.py
@@ -0,0 +1,143 @@
+import os.path
+# Compatibility import
+from Bcfg2.Bcfg2Py3k import ConfigParser
+
+PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
+
+c = ConfigParser.ConfigParser()
+#This needs to be configurable one day somehow
+c.read(['./bcfg2.conf'])
+
+defaults = {'database_engine':'sqlite3',
+ 'database_name':'./dev.db',
+ 'database_user':'',
+ 'database_password':'',
+ 'database_host':'',
+ 'database_port':3306,
+ 'default_mx':'localhost',
+ 'priority':10,
+ 'authorized_group':'admins',
+ }
+
+if c.has_section('hostbase'):
+ options = dict(c.items('hostbase'))
+else:
+ options = defaults
+
+# Django settings for Hostbase project.
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+ADMINS = (
+ ('Root', 'root'),
+)
+MANAGERS = ADMINS
+
+# 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'.
+DATABASE_ENGINE = options['database_engine']
+# Or path to database file if using sqlite3.
+DATABASE_NAME = options['database_name']
+# Not used with sqlite3.
+DATABASE_USER = options['database_user']
+# Not used with sqlite3.
+DATABASE_PASSWORD = options['database_password']
+# Set to empty string for localhost. Not used with sqlite3.
+DATABASE_HOST = options['database_host']
+# Set to empty string for default. Not used with sqlite3.
+DATABASE_PORT = int(options['database_port'])
+# Local time zone for this installation. All choices can be found here:
+# http://docs.djangoproject.com/en/dev/ref/settings/#time-zone
+try:
+ TIME_ZONE = c.get('statistics', 'time_zone')
+except:
+ TIME_ZONE = None
+
+# enter the defauly MX record machines will get in Hostbase
+# this setting may move elsewhere eventually
+DEFAULT_MX = options['default_mx']
+PRIORITY = int(options['priority'])
+
+SESSION_EXPIRE_AT_BROWSER_CLOSE = True
+
+# Uncomment a backend below if you would like to use it for authentication
+AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
+ 'Bcfg2.Server.Hostbase.backends.NISBackend',
+ #'Bcfg2.Server.Hostbase.backends.LDAPBacken',
+ )
+# enter an NIS group name you'd like to give access to edit hostbase records
+AUTHORIZED_GROUP = options['authorized_group']
+
+#create login url area:
+import django.contrib.auth
+django.contrib.auth.LOGIN_URL = '/login'
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')
+# Just for development
+SERVE_MEDIA = DEBUG
+
+# Language code for this installation. All choices can be found here:
+# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
+# http://blogs.law.harvard.edu/tech/stories/storyReader$15
+LANGUAGE_CODE = 'en-us'
+SITE_ID = 1
+# URL that handles the media served from MEDIA_ROOT.
+# Example: "http://media.lawrence.com"
+MEDIA_URL = '/site_media/'
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/media/'
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = '*%=fv=yh9zur&gvt4&*d#84o(cy^-*$ox-v1e9%32pzf2*qu#s'
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.load_template_source',
+ 'django.template.loaders.app_directories.load_template_source',
+# 'django.template.loaders.eggs.load_template_source',
+)
+
+TEMPLATE_CONTEXT_PROCESSORS = (
+ "django.core.context_processors.auth",
+ "django.core.context_processors.debug",
+ "django.core.context_processors.i18n",
+ "django.core.context_processors.request",
+ "django.core.context_processors.media",
+# Django development version.
+# "django.core.context_processors.csrf",
+)
+
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.locale.LocaleMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.middleware.doc.XViewMiddleware',
+)
+
+ROOT_URLCONF = 'Bcfg2.Server.Hostbase.urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates".
+ # Always use forward slashes, even on Windows.
+ '/usr/lib/python2.3/site-packages/Bcfg2/Server/Hostbase/hostbase/webtemplates',
+ '/usr/lib/python2.4/site-packages/Bcfg2/Server/Hostbase/hostbase/webtemplates',
+ '/usr/lib/python2.3/site-packages/Bcfg2/Server/Hostbase/templates',
+ '/usr/lib/python2.4/site-packages/Bcfg2/Server/Hostbase/templates',
+ '/usr/share/bcfg2/Hostbase/templates',
+ os.path.join(PROJECT_ROOT, 'templates'),
+ os.path.join(PROJECT_ROOT, 'hostbase/webtemplates'),
+)
+
+INSTALLED_APPS = (
+ 'django.contrib.admin',
+ 'django.contrib.admindocs',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.humanize',
+ 'Bcfg2.Server.Hostbase.hostbase',
+)
+
+LOGIN_URL = '/login/'
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/batchadd.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/batchadd.tmpl
new file mode 100644
index 000000000..74ea3c047
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/batchadd.tmpl
@@ -0,0 +1,29 @@
+#mx ->
+#priority ->
+
+hostname ->
+whatami ->
+netgroup ->
+security_class ->
+support ->
+csi ->
+printq ->
+dhcp ->
+outbound_smtp ->
+primary_user ->
+administrator ->
+location ->
+expiration_date -> YYYY-MM-DD
+comments ->
+
+mac_addr ->
+hdwr_type ->
+ip_addr ->
+#ip_addr ->
+cname ->
+#cname ->
+
+#mac_addr ->
+#hdwr_type ->
+#ip_addr ->
+#cname ->
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.conf.head b/src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.conf.head
new file mode 100644
index 000000000..a3d19547e
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.conf.head
@@ -0,0 +1,5 @@
+#
+# dhcpd.conf
+#
+# Configuration file for ISC dhcpd
+#
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.tmpl
new file mode 100644
index 000000000..757b263cd
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/dhcpd.tmpl
@@ -0,0 +1,17 @@
+#
+# This file is automatically generated.
+# DO NOT EDIT IT BY HAND!
+#
+# This file contains {{ numips }} IP addresses
+# Generated on: {% now "r" %}
+#
+
+{% include "dhcpd.conf.head" %}
+
+# Hosts which require special configuration options can be listed in
+# host statements. If no address is specified, the address will be
+# allocated dynamically (if possible), but the host-specific information
+# will still come from the host declaration.
+
+{% for host in hosts %}host {{ host.0 }} {hardware ethernet {{ host.1 }};fixed-address {{ host.2 }};}
+{% endfor %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/hosts.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/hosts.tmpl
new file mode 100644
index 000000000..251cb5a79
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/hosts.tmpl
@@ -0,0 +1,26 @@
+##############################################################################
+# MCS hosts file
+#
+# This file is generated automatically - DO NOT EDIT IT.
+#
+# Generated on: {% now "r" %}
+#
+
+127.0.0.1 localhost.mcs.anl.gov localhost
+
+# This file lists hosts in these domains:
+{% for domain in domain_data %}# {{ domain.0 }}: {{ domain.1 }}
+{% endfor %}
+#
+# This file lists hosts on these networks:
+#
+# Network Hosts
+# ---------------------------------------------------------------------
+{% for octet in two_octets_data %}# {{ octet.0 }} {{octet.1 }}
+{% endfor %}
+#
+{% for octet in three_octets_data %}# {{ octet.0 }} {{ octet.1 }}
+{% endfor %}
+#
+# Total host interfaces (ip addresses) in this file: {{ num_ips }}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/hostsappend.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/hostsappend.tmpl
new file mode 100644
index 000000000..00e0d5d04
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/hostsappend.tmpl
@@ -0,0 +1,5 @@
+##########################################################################
+# Hosts on subnet: {{ subnet.0 }}
+# total hosts: {{ subnet.1 }}
+{% for ip in ips %}{{ ip.0 }} {{ ip.1 }}{% if ip.4 and not ip.3 %} # {{ ip.5 }}{% else %}{% for name in ip.2 %} {{ name }}{% endfor %}{% for cname in ip.3 %} {{ cname }}{% endfor %} # {{ ip.5 }}{% endif %}
+{% endfor %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/named.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/named.tmpl
new file mode 100644
index 000000000..03e054198
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/named.tmpl
@@ -0,0 +1,69 @@
+// This is the primary configuration file for the BIND DNS server named.
+//
+// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
+// structure of BIND configuration files in Debian, *BEFORE* you customize
+// this configuration file.
+//
+
+include "/etc/bind/named.conf.options";
+
+include "/etc/bind/rndc.key";
+
+// prime the server with knowledge of the root servers
+zone "." {
+ type hint;
+ file "/etc/bind/db.root";
+};
+
+// be authoritative for the localhost forward and reverse zones, and for
+// broadcast zones as per RFC 1912
+{% for zone in zones %}
+zone "{{ zone.1 }}" {
+ type master;
+ file "/etc/bind/hostbase/{{ zone.1 }}";
+ notify no;
+ also-notify { 140.221.9.6;140.221.8.10; };
+};{% endfor %}
+
+zone "localhost" {
+ type master;
+ file "/etc/bind/db.local";
+};
+
+zone "127.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.127";
+};
+
+zone "0.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0";
+};
+
+zone "255.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.255";
+};
+{% for reverse in reverses %}
+zone "{{ reverse.0 }}.in-addr.arpa" {
+ type master;
+ file "/etc/bind/hostbase/{{ reverse.0 }}.rev";
+ notify no;
+ also-notify { 140.221.9.6;140.221.8.10; };
+};{% endfor %}
+
+// zone "com" { type delegation-only; };
+// zone "net" { type delegation-only; };
+
+// From the release notes:
+// Because many of our users are uncomfortable receiving undelegated answers
+// from root or top level domains, other than a few for whom that behaviour
+// has been trusted and expected for quite some length of time, we have now
+// introduced the "root-delegations-only" feature which applies delegation-only
+// logic to all top level domains, and to the root domain. An exception list
+// should be specified, including "MUSEUM" and "DE", and any other top level
+// domains from whom undelegated responses are expected and trusted.
+// root-delegation-only exclude { "DE"; "MUSEUM"; };
+
+include "/etc/bind/named.conf.local";
+include "/etc/bind/named.conf.static";
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/namedviews.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/namedviews.tmpl
new file mode 100644
index 000000000..52021620e
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/namedviews.tmpl
@@ -0,0 +1,92 @@
+// This is the primary configuration file for the BIND DNS server named.
+//
+// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
+// structure of BIND configuration files in Debian, *BEFORE* you customize
+// this configuration file.
+//
+
+include "/etc/bind/named.conf.options";
+
+include "/etc/bind/rndc.key";
+
+view "internal" {
+ match-clients { 140.221.9.6;140.221.8.10;140.221.8.88;140.221.8.15; };
+ recursion yes;
+ // prime the server with knowledge of the root servers
+ zone "." {
+ type hint;
+ file "/etc/bind/db.root";
+ };
+ {% for zone in zones %}
+ zone "{{ zone.1 }}" {
+ type master;
+ file "/etc/bind/hostbase/{{ zone.1 }}";
+ notify no;
+ also-notify { 140.221.9.6;140.221.8.10;140.221.8.88;140.221.8.15; };
+ };{% endfor %}
+ // be authoritative for the localhost forward and reverse zones, and for
+ // broadcast zones as per RFC 1912
+
+ zone "localhost" {
+ type master;
+ file "/etc/bind/db.local";
+ };
+
+ zone "127.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.127";
+ };
+
+ zone "0.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.0";
+ };
+
+ zone "255.in-addr.arpa" {
+ type master;
+ file "/etc/bind/db.255";
+ };
+ {% for reverse in reverses %}
+ zone "{{ reverse.0 }}.in-addr.arpa" {
+ type master;
+ file "/etc/bind/hostbase/{{ reverse.0 }}.rev";
+ notify no;
+ also-notify { 140.221.9.6;140.221.8.10;140.221.8.88; };
+ };{% endfor %}
+ include "/etc/bind/named.conf.static";
+};
+
+view "external" {
+ match-clients { any; };
+ recursion no;
+ {% for zone in zones %}
+ zone "{{ zone.1 }}" {
+ type master;
+ file "/etc/bind/hostbase/{{ zone.1 }}.external";
+ notify no;
+ };{% endfor %}
+
+ {% for reverse in reverses %}
+ zone "{{ reverse.0 }}.in-addr.arpa" {
+ type master;
+ file "/etc/bind/hostbase/{{ reverse.0 }}.rev.external";
+ notify no;
+ };{% endfor %}
+ include "/etc/bind/named.conf.static";
+};
+
+
+// zone "com" { type delegation-only; };
+// zone "net" { type delegation-only; };
+
+// From the release notes:
+// Because many of our users are uncomfortable receiving undelegated answers
+// from root or top level domains, other than a few for whom that behaviour
+// has been trusted and expected for quite some length of time, we have now
+// introduced the "root-delegations-only" feature which applies delegation-only
+// logic to all top level domains, and to the root domain. An exception list
+// should be specified, including "MUSEUM" and "DE", and any other top level
+// domains from whom undelegated responses are expected and trusted.
+// root-delegation-only exclude { "DE"; "MUSEUM"; };
+
+include "/etc/bind/named.conf.local";
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/reverseappend.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/reverseappend.tmpl
new file mode 100644
index 000000000..6ed520c98
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/reverseappend.tmpl
@@ -0,0 +1,4 @@
+{% if fileorigin %}$ORIGIN {{ fileorigin }}.in-addr.arpa.{% endif %}
+$ORIGIN {{ inaddr }}.in-addr.arpa.
+{% for host in hosts %}{{ host.0.3 }} PTR {{ host.1 }}.
+{% endfor %}
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/reversesoa.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/reversesoa.tmpl
new file mode 100644
index 000000000..d142eaf7f
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/reversesoa.tmpl
@@ -0,0 +1,13 @@
+$ORIGIN .
+$TTL {{ zone.8 }}
+{{ inaddr }}.in-addr.arpa IN SOA {{ zone.4 }}. {{ zone.3 }} (
+ {{ zone.2 }} ; serial
+ {{ zone.7 }} ; refresh interval
+ {{ zone.6 }} ; retry interval
+ {{ zone.5 }} ; expire interval
+ {{ zone.8 }} ; min ttl
+ )
+
+ {% for ns in nameservers %}NS {{ ns.0 }}
+ {% endfor %}
+
diff --git a/src/lib/Bcfg2/Server/Hostbase/templates/zone.tmpl b/src/lib/Bcfg2/Server/Hostbase/templates/zone.tmpl
new file mode 100644
index 000000000..aad48d179
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/templates/zone.tmpl
@@ -0,0 +1,18 @@
+$ORIGIN .
+$TTL {{ zone.8 }}
+{{ zone.1 }}. IN SOA {{ zone.4 }}. {{ zone.3 }}. (
+ {{ zone.2 }} ; serial
+ {{ zone.7 }} ; refresh interval
+ {{ zone.6 }} ; retry interval
+ {{ zone.5 }} ; expire interval
+ {{ zone.8 }} ; min ttl
+ )
+
+ {% for ns in nameservers %}NS {{ ns.0 }}
+ {% endfor %}
+ {% for a in addresses %}A {{ a.0 }}
+ {% endfor %}
+ {% for mx in mxs %}MX {{ mx.0 }} {{ mx.1 }}
+ {% endfor %}
+$ORIGIN {{ zone.1 }}.
+localhost A 127.0.0.1
diff --git a/src/lib/Bcfg2/Server/Hostbase/test/harness.py b/src/lib/Bcfg2/Server/Hostbase/test/harness.py
new file mode 100644
index 000000000..befcff5c0
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/test/harness.py
@@ -0,0 +1,11 @@
+import os, sys
+
+here = os.path.realpath('harness')
+
+server_hostbase = os.path.realpath(here + '../../../../')
+
+sys.path.insert(0,server_hostbase)
+sys.path.insert(0,server_hostbase + '../')
+#commented this out, but might be needed for now until the harness is figured out
+#if so, use your actual path to the Hostbase module
+#sys.path.insert(0,'/home/dahl/Code/bcfg2/src/lib/Server/Hostbase')
diff --git a/src/lib/Bcfg2/Server/Hostbase/test/test_environ_settings.py b/src/lib/Bcfg2/Server/Hostbase/test/test_environ_settings.py
new file mode 100644
index 000000000..ad35c624e
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/test/test_environ_settings.py
@@ -0,0 +1,35 @@
+import sys
+import os
+
+
+def env_setup():
+ os.environ['bcfg_db_engine'] = 'foo'
+ os.environ['bcfg_db_name'] = 'bar'
+ os.environ['bcfg_db_user'] = 'baz'
+ os.environ['bcfg_db_password'] = 'pass'
+ os.environ['bcfg_db_host'] = 'biff'
+ os.environ['bcfg_db_port'] = '3306'
+ os.environ['bcfg_time_zone'] = 'CHI'
+
+def teardown():
+ pass
+
+def test_environ_settings():
+
+ os.environ['bcfg_db_engine'] = 'foo'
+ os.environ['bcfg_db_name'] = 'bar'
+ os.environ['bcfg_db_user'] = 'baz'
+ os.environ['bcfg_db_password'] = 'pass'
+ os.environ['bcfg_db_host'] = 'biff'
+ os.environ['bcfg_db_port'] = '3306'
+ os.environ['bcfg_time_zone'] = 'CHI'
+ import Hostbase.settings
+ s = Hostbase.settings
+ s.CFG_TYPE = 'environ'
+ assert s.DATABASE_ENGINE == 'mysql'
+ assert s.DATABASE_PASSWORD == 'pass'
+ assert s.DATABASE_NAME == 'bar'
+ assert s.DATABASE_USER == 'baz'
+ assert s.DATABASE_HOST == 'biff'
+ assert s.DATABASE_PORT == '3306'
+ assert s.TIME_ZONE == 'CHI'
diff --git a/src/lib/Bcfg2/Server/Hostbase/test/test_ldapauth.py b/src/lib/Bcfg2/Server/Hostbase/test/test_ldapauth.py
new file mode 100644
index 000000000..7fc009ad2
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/test/test_ldapauth.py
@@ -0,0 +1,10 @@
+import os,sys
+import harness
+
+from Hostbase.ldapauth import *
+
+def test_it():
+ l = ldapauth(os.environ['LDAP_SVC_ACCT_NAME'],
+ os.environ['LDAP_SVC_ACCT_PASS'])
+
+ assert l.department == 'foo'
diff --git a/src/lib/Bcfg2/Server/Hostbase/test/test_settings.py b/src/lib/Bcfg2/Server/Hostbase/test/test_settings.py
new file mode 100644
index 000000000..0dfc30f38
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/test/test_settings.py
@@ -0,0 +1,12 @@
+import sys
+import os
+import Hostbase.settings
+
+def setup():
+ pass
+
+def teardown():
+ pass
+
+def test_mcs_settings():
+ pass
diff --git a/src/lib/Bcfg2/Server/Hostbase/urls.py b/src/lib/Bcfg2/Server/Hostbase/urls.py
new file mode 100644
index 000000000..01fe97d4f
--- /dev/null
+++ b/src/lib/Bcfg2/Server/Hostbase/urls.py
@@ -0,0 +1,27 @@
+from django.conf.urls.defaults import *
+from django.conf import settings
+from django.views.generic.simple import direct_to_template
+from django.contrib import admin
+
+
+admin.autodiscover()
+
+
+urlpatterns = patterns('',
+ # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
+ # to INSTALLED_APPS 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)),
+
+ (r'^$',direct_to_template, {'template':'index.html'}, 'index'),
+ (r'^hostbase/', include('hostbase.urls')),
+ (r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
+ (r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'})
+)
+
+if settings.SERVE_MEDIA:
+ urlpatterns += patterns('',
+ (r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
+ dict(document_root=settings.MEDIA_ROOT)),)