diff options
Diffstat (limited to 'src/lib/Bcfg2/Server/Hostbase')
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)),) |