Jan Dittberner
daf9517a83
* add pydoc in client and domain backend classes * add support for buildutils in setup.py git-svn-id: file:///home/www/usr01/svn/gnuviechadmin/trunk@262 a67ec6bc-e5d5-0310-a910-815c51eb3124
371 lines
16 KiB
Python
371 lines
16 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (C) 2007, 2008 by Jan Dittberner.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
# USA.
|
|
#
|
|
# Version: $Id$
|
|
"""This module defines the code for handling domains."""
|
|
|
|
import datetime
|
|
import os
|
|
|
|
from gnuviechadmin.exceptions import ValidationFailedError
|
|
from gnuviechadmin.backend.settings import config, get_template, \
|
|
get_template_dir, get_template_string
|
|
from gnuviechadmin.backend.BackendTo import Record, Domain
|
|
from gnuviechadmin.backend.BackendEntity import BackendEntity
|
|
from gnuviechadmin.backend.BackendEntityHandler import BackendEntityHandler
|
|
|
|
|
|
class DomainEntity(BackendEntity):
|
|
"""Entity class for DNS domains."""
|
|
|
|
# the valid domain types
|
|
_valid_domain_types = ("MASTER", "SLAVE")
|
|
|
|
def __init__(self, delegate, verbose = False, **kwargs):
|
|
"""Initializes the DomainEntity instance.
|
|
|
|
`delegate` is the corresponding database object.
|
|
If `verbose` is `True` verbose logging is turned on.
|
|
"""
|
|
BackendEntity.__init__(self, delegate, verbose)
|
|
self.ns1 = None
|
|
self.ns2 = None
|
|
self.mxrr = None
|
|
self.ipaddr = None
|
|
for (key, value) in kwargs.items():
|
|
self.__setattr__(key, value)
|
|
if not self.delegateto.type:
|
|
self.delegateto.type = self.getdefaultdomaintype()
|
|
if not self.ns1:
|
|
self.ns1 = config.get('domain', 'defaultns1')
|
|
if not self.ns2:
|
|
self.ns2 = config.get('domain', 'defaultns2')
|
|
if not self.mxrr:
|
|
self.mxrr = config.get('domain', 'defaultmx')
|
|
if not self.ipaddr:
|
|
self.ipaddr = config.get('domain', 'defaultip')
|
|
self.delegateto.type = self.delegateto.type.upper()
|
|
self.validate()
|
|
|
|
def getdefaultdomaintype(self):
|
|
"""Returns the default domain type."""
|
|
return self._valid_domain_types[0]
|
|
|
|
def validate(self):
|
|
"""Validates the consistency if the entity instance and
|
|
dependent entities."""
|
|
BackendEntity.validate(self)
|
|
if not self.delegateto.type in self._valid_domain_types:
|
|
raise ValidationFailedError(
|
|
self, "invalid domain type %s" % (self.delegateto.type))
|
|
if self.delegateto.type == 'SLAVE' and not self.delegateto.master:
|
|
raise ValidationFailedError(
|
|
self, "you have to specify a master for slave domains.")
|
|
if self.delegateto.type == 'MASTER':
|
|
if not self.ns1 or not self.ns2:
|
|
raise ValidationFailedError(
|
|
self, "two nameservers must be specified.")
|
|
if not self.mxrr:
|
|
raise ValidationFailedError(
|
|
self, "a primary mx host must be specified.")
|
|
|
|
def _getnewserial(self, oldserial = None):
|
|
"""Gets a new zone serial number for the DNS domain entity."""
|
|
current = datetime.datetime.now()
|
|
datepart = "%04d%02d%02d" % \
|
|
(current.year, current.month, current.day)
|
|
retval = None
|
|
if oldserial:
|
|
if str(oldserial)[:len(datepart)] == datepart:
|
|
retval = oldserial + 1
|
|
if not retval:
|
|
retval = int("%s01" % (datepart))
|
|
return retval
|
|
|
|
def _getnewsoa(self):
|
|
"""Gets a new SOA record for the DNS domain entity."""
|
|
return '%s %s %d %d %d %d %d' % \
|
|
(self.ns1,
|
|
config.get('domain', 'defaulthostmaster'),
|
|
self._getnewserial(),
|
|
config.getint('domain', 'defaultrefresh'),
|
|
config.getint('domain', 'defaultretry'),
|
|
config.getint('domain', 'defaultexpire'),
|
|
config.getint('domain', 'defaultminimumttl'))
|
|
|
|
def update_serial(self, session):
|
|
"""Updates the serial of the domain."""
|
|
query = session.query(Record)
|
|
soarecord = query.get_by(Record.c.type == 'SOA',
|
|
Record.c.domainid == self.delegateto.domainid)
|
|
parts = soarecord.content.split(" ")
|
|
parts[2] = str(self._getnewserial(int(parts[2])))
|
|
soarecord.content = " ".join(parts)
|
|
session.save(soarecord)
|
|
session.flush()
|
|
|
|
def _get_vhost_dir(self):
|
|
"""Gets the directory name for the Apache VirtualHost of the
|
|
domain."""
|
|
return os.path.join(self.delegateto.sysuser.home,
|
|
self.delegateto.name,
|
|
config.get('domain', 'htdir'))
|
|
|
|
def _get_log_dir(self):
|
|
"""Gets the Apache log file directory for the domain."""
|
|
return os.path.join(config.get('domain', 'logpath'),
|
|
self.delegateto.name)
|
|
|
|
def _get_stats_dir(self):
|
|
"""Gets the statistics dir for the domain."""
|
|
return os.path.join(config.get('domain', 'statspath'),
|
|
self.delegateto.name)
|
|
|
|
def _create_vhost_dir(self):
|
|
"""Creates the Apache VirtualHost directory for the domain."""
|
|
vhostdir = self._get_vhost_dir()
|
|
self.logger.debug("creating virtual host dir %s" % (vhostdir))
|
|
cmd = 'mkdir -p "%s"' % (vhostdir)
|
|
self.sucommand(cmd)
|
|
for tpl in [tpl for tpl in os.listdir(
|
|
get_template_dir(config.get('domain', 'htdocstemplate'))) \
|
|
if not tpl.startswith('.')]:
|
|
self.logger.debug("processing template %s" % (tpl))
|
|
template = get_template(config.get('domain', 'htdocstemplate'),
|
|
tpl)
|
|
template = template.substitute({
|
|
'domain': self.delegateto.name})
|
|
self.write_to_file(os.path.join(vhostdir, tpl), template)
|
|
cmd = 'chown -R %(username)s:%(group)s "%(dir)s"' % {
|
|
'username': self.delegateto.sysuser.username,
|
|
'group': config.get('sysuser', 'defaultgroup'),
|
|
'dir': vhostdir}
|
|
self.sucommand(cmd)
|
|
|
|
def _create_log_dir(self):
|
|
"""Creates the Apache log file directory for the domain."""
|
|
cmd = 'mkdir -p "%s"' % (self._get_log_dir())
|
|
self.sucommand(cmd)
|
|
|
|
def _get_auth_userfile(self):
|
|
"""Gets the file name of the password file for statistic
|
|
logins for the domain."""
|
|
authdir = config.get('domain', 'authdir')
|
|
if not os.path.isdir(authdir):
|
|
cmd = 'mkdir -p "%s"' % (authdir)
|
|
self.sucommand(cmd)
|
|
return os.path.join(authdir, '%s.passwd' % (self.delegateto.name))
|
|
|
|
def _create_stats_dir(self):
|
|
"""Creates the statistics directory for the domain and sets
|
|
Apache .htaccess password protection."""
|
|
statsdir = self._get_stats_dir()
|
|
authfile = self._get_auth_userfile()
|
|
cmd = 'htpasswd -m -c -b "%s" "%s" "%s"' % (
|
|
authfile,
|
|
self.delegateto.sysuser.username,
|
|
self.delegateto.sysuser.clearpass)
|
|
self.sucommand(cmd)
|
|
cmd = 'mkdir -p "%s"' % (statsdir)
|
|
self.sucommand(cmd)
|
|
template = get_template(config.get('domain', 'conftemplates'),
|
|
config.get('domain', 'statshtaccesstemplate'))
|
|
template = template.substitute({
|
|
'domain': self.delegateto.name,
|
|
'userfile': authfile})
|
|
self.write_to_file(os.path.join(self._get_stats_dir(),
|
|
'.htaccess'), template)
|
|
|
|
def _create_stats_conf(self):
|
|
"""Creates the modlogan statistics configuration for the
|
|
domain."""
|
|
modlogandir = os.path.join(config.get('domain',
|
|
'modlogandir'),
|
|
self.delegateto.sysuser.username)
|
|
cmd = 'mkdir -p "%s"' % (modlogandir)
|
|
self.sucommand(cmd)
|
|
template = get_template(config.get('domain', 'conftemplates'),
|
|
config.get('domain', 'modlogantemplate'))
|
|
template = template.substitute({
|
|
'statsdir': self._get_stats_dir(),
|
|
'logdir': self._get_log_dir(),
|
|
'domain': self.delegateto.name,
|
|
'domainesc': self.delegateto.name.replace('.', '\.')})
|
|
self.write_to_file(os.path.join(modlogandir,
|
|
self.delegateto.name + '.conf'),
|
|
template)
|
|
|
|
def _create_apache_conf(self):
|
|
"""Creates the Apache configuration file for the domain."""
|
|
template = get_template(config.get('domain', 'conftemplates'),
|
|
config.get('domain', 'apachetemplate'))
|
|
template = template.substitute({
|
|
'ipaddr': self.ipaddr,
|
|
'statsdir': self._get_stats_dir(),
|
|
'logdir': self._get_log_dir(),
|
|
'domain': self.delegateto.name,
|
|
'docroot': self._get_vhost_dir()})
|
|
self.write_to_file(os.path.join(config.get('domain', 'sitesdir'),
|
|
self.delegateto.name), template)
|
|
|
|
def _mail_domain(self):
|
|
"""Mail a summary of the domain data."""
|
|
template = get_template(config.get('common', 'mailtemplates'),
|
|
config.get('domain', 'create.mail'))
|
|
text = template.substitute({
|
|
'sysuser': self.delegateto.sysuser.username,
|
|
'domain': self.delegateto.name,
|
|
'docroot': self._get_vhost_dir(),
|
|
'statspass': self.delegateto.sysuser.clearpass})
|
|
template = get_template_string(config.get('domain', 'create_subject'))
|
|
subject = template.substitute({
|
|
'domain': self.delegateto.name})
|
|
self.send_mail(subject, text)
|
|
|
|
def create_hook(self, session):
|
|
"""Hook for the creation of the domain.
|
|
|
|
This method is called by
|
|
`gnuviechadmin.backend.BackendEntityHandler.create()`.
|
|
"""
|
|
self.delegateto.records.append(Record(
|
|
name = self.delegateto.name, type = 'SOA',
|
|
content = self._getnewsoa(),
|
|
ttl = config.getint('domain', 'defaultttl')))
|
|
self.delegateto.records.append(Record(
|
|
name = self.delegateto.name, type = 'NS', content = self.ns1,
|
|
ttl = config.getint('domain', 'defaultttl')))
|
|
self.delegateto.records.append(Record(
|
|
name = self.delegateto.name, type = 'NS', content = self.ns2,
|
|
ttl = config.getint('domain', 'defaultttl')))
|
|
self.delegateto.records.append(Record(
|
|
name = self.delegateto.name, type = 'MX', content = self.mxrr,
|
|
ttl = config.getint('domain', 'defaultttl'),
|
|
prio = config.getint('domain', 'defaultmxprio')))
|
|
self.delegateto.records.append(Record(
|
|
name = self.delegateto.name, type = 'A', content = self.ipaddr,
|
|
ttl = config.getint('domain', 'defaultttl')))
|
|
self.delegateto.records.append(Record(
|
|
name = "www.%s" % (self.delegateto.name), type = 'A',
|
|
content = self.ipaddr,
|
|
ttl = config.getint('domain', 'defaultttl')))
|
|
session.save_or_update(self.delegateto)
|
|
session.flush()
|
|
self._create_vhost_dir()
|
|
self._create_log_dir()
|
|
self._create_stats_dir()
|
|
self._create_stats_conf()
|
|
self._create_apache_conf()
|
|
self._mail_domain()
|
|
|
|
def _delete_apache_conf(self):
|
|
"""Deletes the Apache configuration file for the domain."""
|
|
cmd = 'a2dissite %s' % (self.delegateto.name)
|
|
self.sucommand(cmd)
|
|
cmd = 'rm "%s"' % (os.path.join(config.get('domain', 'sitesdir'),
|
|
self.delegateto.name))
|
|
self.sucommand(cmd)
|
|
|
|
def _delete_stats_conf(self):
|
|
"""Deletes the modlogan stastics configuration for the
|
|
domain."""
|
|
cmd = 'rm "%s"' % (os.path.join(config.get('domain', 'modlogandir'),
|
|
self.delegateto.sysuser.username,
|
|
self.delegateto.name + '.conf'))
|
|
self.sucommand(cmd)
|
|
|
|
def _archive_stats_dir(self):
|
|
"""Archives the statistics directory for the domain."""
|
|
archive = os.path.join(self.delegateto.sysuser.home,
|
|
'%(domain)s-stats.tar.gz' % {
|
|
'domain': self.delegateto.name})
|
|
cmd = 'tar czf "%(archive)s" --directory="%(statsbase)s" ' + \
|
|
'"%(statsdir)s"' % {
|
|
'archive': archive,
|
|
'statsbase': config.get('domain', 'statspath'),
|
|
'statsdir': self.delegateto.name}
|
|
self.sucommand(cmd)
|
|
cmd = 'rm -r "%(statsdir)s"' % {
|
|
'statsdir': self._get_stats_dir()}
|
|
self.sucommand(cmd)
|
|
cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % {
|
|
'username': self.delegateto.sysuser.username,
|
|
'group': config.get('sysuser', 'defaultgroup'),
|
|
'archive': archive}
|
|
self.sucommand(cmd)
|
|
|
|
def _archive_log_dir(self):
|
|
"""Archives the Apache log file directory for the domain."""
|
|
archive = os.path.join(self.delegateto.sysuser.home,
|
|
'%(domain)s-logs.tar.gz' % {
|
|
'domain': self.delegateto.name})
|
|
cmd = 'tar czf "%(archive)s" --directory="%(logbase)s" ' + \
|
|
'"%(logdir)s"' % {
|
|
'archive': archive,
|
|
'logbase': config.get('domain', 'logpath'),
|
|
'logdir': self.delegateto.name}
|
|
self.sucommand(cmd)
|
|
cmd = 'rm -r "%(logdir)s"' % {
|
|
'logdir': self._get_log_dir()}
|
|
self.sucommand(cmd)
|
|
cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % {
|
|
'username': self.delegateto.sysuser.username,
|
|
'group': config.get('sysuser', 'defaultgroup'),
|
|
'archive': archive}
|
|
self.sucommand(cmd)
|
|
|
|
def _archive_vhost_dir(self):
|
|
"""Archives the Apache VirtualHost directory for the domain."""
|
|
archive = os.path.join(self.delegateto.sysuser.home,
|
|
'%(domain)s-vhost.tar.gz' % {
|
|
'domain': self.delegateto.name})
|
|
cmd = 'tar czf "%(archive)s" --directory="%(vhostbase)s" ' + \
|
|
'"%(vhostdir)s"' % {
|
|
'archive': archive,
|
|
'vhostbase': self.delegateto.sysuser.home,
|
|
'vhostdir': self.delegateto.name}
|
|
self.sucommand(cmd)
|
|
cmd = 'rm -r "%(vhostdir)s"' % {
|
|
'vhostdir': os.path.join(self.delegateto.sysuser.home,
|
|
self.delegateto.name)}
|
|
self.sucommand(cmd)
|
|
cmd = 'chown "%(username)s:%(group)s" "%(archive)s"' % {
|
|
'username': self.delegateto.sysuser.username,
|
|
'group': config.get('sysuser', 'defaultgroup'),
|
|
'archive': archive}
|
|
self.sucommand(cmd)
|
|
|
|
def delete_hook(self, session):
|
|
"""Deletes domain related files and directories.
|
|
|
|
This method is called by `BackendEntityHandler.delete()`.
|
|
"""
|
|
self._delete_apache_conf()
|
|
self._delete_stats_conf()
|
|
self._archive_stats_dir()
|
|
self._archive_log_dir()
|
|
self._archive_vhost_dir()
|
|
|
|
|
|
class DomainHandler(BackendEntityHandler):
|
|
"""BackendEntityHandler for Domain entities."""
|
|
|
|
def __init__(self, verbose = False):
|
|
"""Initialize the DomainHandler."""
|
|
BackendEntityHandler.__init__(self, DomainEntity, Domain, verbose)
|