1
0
Fork 0

Code style changes

* make code PEP8 clean (addresses #18)
 * add copyright information to all python files


git-svn-id: file:///home/www/usr01/svn/gnuviechadmin/trunk@257 a67ec6bc-e5d5-0310-a910-815c51eb3124
This commit is contained in:
Jan Dittberner 2008-06-06 19:20:18 +00:00
parent 7c4d25da43
commit 09180938f1
45 changed files with 759 additions and 514 deletions

View File

@ -1,7 +1,8 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 by Jan Dittberner.
# 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

View File

@ -18,8 +18,7 @@ client = Table(
Column('mobile', String(32)),
Column('fax', String(32)),
Column('email', String(64), unique=True, nullable=False),
schema = dbschema
)
schema = dbschema)
sysuser = Table(
'sysuser', meta,
Column('sysuserid', Integer, primary_key=True),
@ -33,8 +32,7 @@ sysuser = Table(
nullable=False),
Column('sysuid', Integer, nullable=False, unique=True),
Column('lastchange', DateTime, default=func.now()),
schema = dbschema
)
schema = dbschema)
domain = Table(
'domain', meta,
Column('domainid', Integer, primary_key=True),
@ -45,8 +43,7 @@ domain = Table(
Column('notified_serial', Integer),
Column('sysuserid', Integer, ForeignKey(sysuser.c.sysuserid),
nullable=False),
schema = dbschema
)
schema = dbschema)
record = Table(
'record', meta,
Column('recordid', Integer, primary_key=True),
@ -58,16 +55,15 @@ record = Table(
Column('ttl', Integer),
Column('prio', Integer),
Column('change_date', Integer),
schema = dbschema
)
schema = dbschema)
supermaster = Table(
'supermaster', meta,
Column('ip', String(25), nullable=False),
Column('nameserver', String(255), nullable=False),
Column('account', Integer, ForeignKey(sysuser.c.sysuserid),
nullable=False),
schema = dbschema
)
schema = dbschema)
def upgrade():
client.create()
@ -76,6 +72,7 @@ def upgrade():
record.create()
supermaster.create()
def downgrade():
supermaster.drop()
record.drop()

View File

@ -17,8 +17,7 @@ mailaccount = Table(
Column('home', String(128), nullable = False),
Column('spamcheck', Boolean, nullable = False, default = False),
Column('sajunkscore', Integer),
schema = dbschema
)
schema = dbschema)
mailaddress = Table(
'mailaddress', meta,
Column('mailaddressid', Integer, primary_key = True),
@ -26,8 +25,7 @@ mailaddress = Table(
nullable = False),
Column('email', String(255), nullable = False),
UniqueConstraint('email', 'domainid'),
schema = dbschema
)
schema = dbschema)
mailtarget = Table(
'mailtarget', meta,
Column('mailtargetid', Integer, primary_key = True),
@ -35,14 +33,15 @@ mailtarget = Table(
nullable = False),
Column('target', String(128), nullable = False),
UniqueConstraint('target', 'mailaddressid'),
schema = dbschema
)
schema = dbschema)
def upgrade():
mailaccount.create()
mailaddress.create()
mailtarget.create()
def downgrade():
mailtarget.drop()
mailaddress.drop()

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -20,7 +19,9 @@
#
# Version: $Id$
import os, logging, tempfile
import os
import logging
import tempfile
from settings import config
from gnuviechadmin.exceptions import *
@ -29,6 +30,7 @@ from subprocess import *
import sqlalchemy
from sqlalchemy.orm import object_mapper
class BackendEntity(object):
"""This is the abstract base class for all backend entity classes."""
@ -75,10 +77,10 @@ class BackendEntity(object):
for cmdline in cmdlines:
toexec = "%s %s" % (suwrapper, cmdline)
if predecessor is None:
p = Popen(toexec, shell = True, stdout = PIPE)
p = Popen(toexec, shell = True, stdout = PIPE)
else:
p = Popen(toexec, shell = True, stdin = predecessor.stdout,
stdout = PIPE)
p = Popen(toexec, shell = True, stdin = predecessor.stdout,
stdout = PIPE)
predecessor = p
output = predecessor.communicate()[0]
return predecessor.wait()
@ -110,4 +112,3 @@ class BackendEntity(object):
cmd = 'cp "%s" "%s"' % (tmp.name, filename)
self.sucommand(cmd)
tmp.close()

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -20,12 +19,15 @@
#
# Version: $Id$
import sqlalchemy, logging
import sqlalchemy
import logging
from sqlalchemy.orm import create_session
from gnuviechadmin.exceptions import *
from BackendEntity import *
class BackendEntityHandler(object):
def __init__(self, entityclass, toclass, verbose = False):
self.logger = logging.getLogger("%s.%s" % (
self.__class__.__module__, self.__class__.__name__))
@ -40,7 +42,7 @@ class BackendEntityHandler(object):
sess = create_session()
transaction = sess.create_transaction()
delegate = self.toclass(**kwargs)
entity = self.entityclass(delegate, self.verbose)
entity = self.entityclass(delegate, self.verbose)
try:
sess.save(delegate)
sess.flush()

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -21,11 +20,12 @@
# Version: $Id$
from sqlalchemy.orm import object_mapper, mapper, relation
from tables import *
class BackendTo(object):
"""Backend transfer object class."""
def __init__(self, **kwargs):
for (key, value) in kwargs.items():
self.__setattr__(key, value)
@ -37,7 +37,7 @@ class BackendTo(object):
format = "%(class)s:"
format = format + ", ".join([col + "=%(" + col + ")s" for col in \
cols])
data = {'class' : self.__class__.__name__}
data = {'class': self.__class__.__name__}
else:
cols = self._shortkeys
format = ",".join("%(" + col + ")s" for col in cols)
@ -45,30 +45,31 @@ class BackendTo(object):
data.update(dict([(col, self.__getattribute__(col)) for col in cols]))
return format % data
class Client(BackendTo):
"""Transfer object class for clients."""
_shortkeys = ('clientid', 'firstname', 'lastname', 'email')
class Sysuser(BackendTo):
"""Transfer object class for system users."""
_shortkeys = ("sysuserid", "clientid", "username", "home", "shell")
class Domain(BackendTo):
"""Transfer object class for DNS domains."""
_shortkeys = ("domainid", "sysuserid", "name", "type")
class Record(BackendTo):
"""Transfer object class for DNS domain records."""
_shortkeys = ("recordid", "domainid", "name", "type", "content")
client_mapper = mapper(Client, client_table)
sysuser_mapper = mapper(Sysuser, sysuser_table)
domain_mapper = mapper(Domain, domain_table)
client_mapper = mapper(Client, client_table, {
'sysusers': relation(Sysuser, backref = 'client')})
sysuser_mapper = mapper(Sysuser, sysuser_table, {
'domains': relation(Domain, backref = 'sysuser')})
domain_mapper = mapper(Domain, domain_table, {
'records': relation(Record, cascade = 'all', backref = 'domain')})
record_mapper = mapper(Record, record_table)
client_mapper.add_property("sysusers", relation(Sysuser, backref = 'client'))
sysuser_mapper.add_property("domains", relation(Domain, backref = 'sysuser'))
domain_mapper.add_property("records", relation(Record, cascade = 'all',
backref = 'domain'))

View File

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 by Jan Dittberner.
# 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

View File

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 by Jan Dittberner.
# 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
@ -25,6 +25,7 @@ from BackendTo import *
from BackendEntity import *
from BackendEntityHandler import *
class ClientEntity(BackendEntity):
"""Entity class for clients."""
@ -39,18 +40,18 @@ class ClientEntity(BackendEntity):
def _client_mail(self):
text = get_template(config.get('common', 'mailtemplates'),
config.get('client', 'create.mail')).substitute({
'firstname' : self.delegateto.firstname,
'lastname' : self.delegateto.lastname,
'email' : self.delegateto.email,
'address1' : self.delegateto.address1,
'zipcode' : self.delegateto.zip,
'city' : self.delegateto.city,
'phone' : self.delegateto.phone})
'firstname': self.delegateto.firstname,
'lastname': self.delegateto.lastname,
'email': self.delegateto.email,
'address1': self.delegateto.address1,
'zipcode': self.delegateto.zip,
'city': self.delegateto.city,
'phone': self.delegateto.phone})
subject = get_template_string(
config.get('client', 'create_subject')).substitute({
'firstname' : self.delegateto.firstname,
'lastname' : self.delegateto.lastname})
self.send_mail(subject, text)
'firstname': self.delegateto.firstname,
'lastname': self.delegateto.lastname})
self.send_mail(subject, text)
def create_hook(self, session):
"""Actions to perform when a client is created."""
@ -69,6 +70,7 @@ class ClientEntity(BackendEntity):
"""Gets the default country."""
return config.get('common', 'defaultcountry')
class ClientHandler(BackendEntityHandler):
"""BackendEntityHandler for Client entities."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -18,9 +17,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id: client.py 1101 2007-02-28 21:15:20Z jan $
# Version: $Id$
import datetime, os
import datetime
import os
from gnuviechadmin.exceptions import *
from settings import *
@ -28,6 +28,7 @@ from BackendTo import Record, Domain
from BackendEntity import BackendEntity
from BackendEntityHandler import BackendEntityHandler
class DomainEntity(BackendEntity):
"""Entity class for DNS domains."""
@ -130,12 +131,12 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('domain', 'htdocstemplate'),
tpl)
template = template.substitute({
'domain' : self.delegateto.name})
'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}
'username': self.delegateto.sysuser.username,
'group': config.get('sysuser', 'defaultgroup'),
'dir': vhostdir}
self.sucommand(cmd)
def _create_log_dir(self):
@ -164,8 +165,8 @@ class DomainEntity(BackendEntity):
template = get_template(config.get('domain', 'conftemplates'),
config.get('domain', 'statshtaccesstemplate'))
template = template.substitute({
'domain' : self.delegateto.name,
'userfile' : authfile})
'domain': self.delegateto.name,
'userfile': authfile})
self.write_to_file(os.path.join(self._get_stats_dir(),
'.htaccess'), template)
@ -178,10 +179,10 @@ class DomainEntity(BackendEntity):
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('.', '\.')})
'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)
@ -190,11 +191,11 @@ class DomainEntity(BackendEntity):
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()})
'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)
@ -202,14 +203,14 @@ class DomainEntity(BackendEntity):
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})
'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)
'domain': self.delegateto.name})
self.send_mail(subject, text)
def create_hook(self, session):
self.delegateto.records.append(Record(
@ -223,7 +224,7 @@ class DomainEntity(BackendEntity):
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.mx,
name = self.delegateto.name, type = 'MX', content = self.mx,
ttl = config.getint('domain', 'defaultttl'),
prio = config.getint('domain', 'defaultmxprio')))
self.delegateto.records.append(Record(
@ -258,65 +259,69 @@ class DomainEntity(BackendEntity):
def _archive_stats_dir(self):
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}
'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()}
'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}
'username': self.delegateto.sysuser.username,
'group': config.get('sysuser', 'defaultgroup'),
'archive': archive}
self.sucommand(cmd)
def _archive_log_dir(self):
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}
'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()}
'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}
'username': self.delegateto.sysuser.username,
'group': config.get('sysuser', 'defaultgroup'),
'archive': archive}
self.sucommand(cmd)
def _archive_vhost_dir(self):
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}
'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,
'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}
'username': self.delegateto.sysuser.username,
'group': config.get('sysuser', 'defaultgroup'),
'archive': archive}
self.sucommand(cmd)
def delete_hook(self, session):
def delete_hook(self, session):
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."""

View File

@ -1,6 +1,6 @@
# -*- coding: UTF-8 -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 by Jan Dittberner.
# 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
@ -25,16 +25,19 @@ from domain import DomainEntity
from BackendEntity import *
from BackendEntityHandler import *
class RecordEntity(BackendEntity):
"""Entity class for DNS domain records."""
def create_hook(self, session):
domain = session.load(Domain, self.delegateto.domainid)
DomainEntity(domain).update_serial(session)
def delete_hook(self, session):
domain = session.load(Domain, self.delegateto.domainid)
DomainEntity(domain).update_serial(session)
class RecordHandler(BackendEntityHandler):
"""BackendEntityHandler for Record entities."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -26,7 +25,10 @@ This module handles all central configuration of Gnuviech Admin. It
parses configuration files and provides functions for reading
templates."""
import ConfigParser, os, string, logging.config
import ConfigParser
import os
import string
import logging.config
# global settings which must not be user configurable
required_version = 3
@ -40,11 +42,13 @@ dbschema = None
if config.get('database', 'uri').startswith('postgres://'):
dbschema = 'gva'
def get_template_dir(dirname):
"""Returns the template directory for the given directory."""
templatepath = config.get('common', 'templatedir')
return os.path.join(templatepath, dirname)
def get_template(dirname, filename):
"""Returns the template data from the given template file."""
templatefile = file(os.path.join(get_template_dir(dirname),
@ -52,6 +56,7 @@ def get_template(dirname, filename):
templatedata = templatefile.read()
return string.Template(templatedata.decode('utf_8'))
def get_template_string(templatestring):
"""Returns a template object for the given template string."""
return string.Template(templatestring)

View File

@ -27,6 +27,7 @@ from BackendEntity import *
from BackendEntityHandler import *
import os
class SysuserEntity(BackendEntity):
"""Entity class for system users."""
@ -54,7 +55,8 @@ class SysuserEntity(BackendEntity):
usernames = [user.username for user in \
getenttools.find_user_by_prefix(prefix)]
if usernames:
maxid = max([int(username[len(prefix):]) for username in usernames])
maxid = max([int(username[len(prefix):]) \
for username in usernames])
maxid += 2
for number in range(1, maxid):
username = "%s%02d" % (prefix, number)
@ -81,17 +83,18 @@ class SysuserEntity(BackendEntity):
def _get_next_sysuid(self):
return getenttools.get_next_uid(int(config.get('sysuser', 'minuid')),
int(config.get('sysuser', 'maxuid')))
int(config.get('sysuser', 'maxuid')))
def _populate_home(self):
templatedir = get_template_dir(config.get('sysuser', 'hometemplate'))
olddir = os.getcwd()
os.chdir(templatedir)
cmd1 = 'find . -depth \! -regex ".*\.svn.*" \! -name "*~" -print0'
cmd2 = 'cpio --pass-through --owner=%(username)s.%(group)s --null --make-directories %(home)s' % {
'username' : self.delegateto.username,
'group' : config.get('sysuser', 'defaultgroup'),
'home' : self.delegateto.home}
cmd2 = 'cpio --pass-through --owner=%(username)s.%(group)s --null ' + \
'--make-directories %(home)s' % {
'username': self.delegateto.username,
'group': config.get('sysuser', 'defaultgroup'),
'home': self.delegateto.home}
self.supipe((cmd1, cmd2))
os.chdir(olddir)
@ -99,33 +102,35 @@ class SysuserEntity(BackendEntity):
template = get_template(config.get('common', 'mailtemplates'),
config.get('sysuser', 'create.mail'))
text = template.substitute({
'uid' : self.delegateto.sysuid,
'firstname' : self.delegateto.client.firstname,
'lastname' : self.delegateto.client.lastname,
'email' : self.delegateto.client.email,
'username' : self.delegateto.username,
'password' : self.delegateto.clearpass,
'home' : self.delegateto.home,
'shell' : self._get_shell_binary()})
'uid': self.delegateto.sysuid,
'firstname': self.delegateto.client.firstname,
'lastname': self.delegateto.client.lastname,
'email': self.delegateto.client.email,
'username': self.delegateto.username,
'password': self.delegateto.clearpass,
'home': self.delegateto.home,
'shell': self._get_shell_binary()})
template = get_template_string(config.get('sysuser', 'create_subject'))
subject = template.substitute({
'username' : self.delegateto.username})
'username': self.delegateto.username})
self.send_mail(subject, text)
def create_hook(self, session):
gecos = config.get('sysuser', 'gecos') % (self.delegateto.username)
cmdline = 'adduser --home "%(home)s" --shell "%(shell)s" --no-create-home --uid %(sysuid)d --ingroup "%(group)s" --disabled-password --gecos "%(gecos)s" %(username)s' % {
'home' : self.delegateto.home,
'shell' : self._get_shell_binary(),
'sysuid' : self.delegateto.sysuid,
'group' : config.get('sysuser', 'defaultgroup'),
'gecos' : gecos,
'username' : self.delegateto.username}
cmdline = 'adduser --home "%(home)s" --shell "%(shell)s" ' + \
'--no-create-home --uid %(sysuid)d --ingroup "%(group)s" ' + \
'--disabled-password --gecos "%(gecos)s" %(username)s' % {
'home': self.delegateto.home,
'shell': self._get_shell_binary(),
'sysuid': self.delegateto.sysuid,
'group': config.get('sysuser', 'defaultgroup'),
'gecos': gecos,
'username': self.delegateto.username}
self.sucommand(cmdline)
cmdline = 'chpasswd --encrypted'
inline = '%(username)s:%(md5pass)s' % {
'username' : self.delegateto.username,
'md5pass' : self.delegateto.md5pass}
'username': self.delegateto.username,
'md5pass': self.delegateto.md5pass}
self.sucommand(cmdline, inline)
self._populate_home()
self._mail_sysuser()
@ -141,15 +146,17 @@ class SysuserEntity(BackendEntity):
config.get('sysuser', 'homebackupdir'))
if not os.path.isdir(backupdir):
cmdline = 'mkdir -p "%(backupdir)s"' % {
'backupdir' : backupdir}
'backupdir': backupdir}
status = self.sucommand(cmdline)
if status != 0:
raise Exception("could not create backup directory")
cmdline = 'deluser --remove-home --backup --backup-to "%(backupdir)s" %(username)s' % {
'backupdir' : backupdir,
'username' : self.delegateto.username}
cmdline = 'deluser --remove-home --backup --backup-to ' + \
' "%(backupdir)s" %(username)s' % {
'backupdir': backupdir,
'username': self.delegateto.username}
self.sucommand(cmdline)
class SysuserHandler(BackendEntityHandler):
"""BackendEntityHandler for Sysuser entities."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -31,7 +30,8 @@ try:
config.get('database', 'uri'),
config.get('database', 'repository'))
if dbversion < required_version:
print("""Database version is %d but required version is %d. Trying automatic upgrade.""" %
print("""Database version is %d but required version is %d. Trying
automatic upgrade.""" %
(dbversion, required_version))
try:
migrate.versioning.api.upgrade(
@ -42,10 +42,11 @@ try:
print "Automatic upgrade failed."
raise
elif dbversion > required_version:
print("""Database version is %d which is higher than the required version %d. I cannot handle this situation without possible data loss.""" %
print("""Database version is %d which is higher than the required
version %d. I cannot handle this situation without possible data loss.""" %
(dbversion, required_version))
sys.exit(1)
except NoSuchTableError, nste:
except NoSuchTableError, nste:
print """The database is not versioned. Trying automatic versioning."""
try:
migrate.versioning.api.version_control(

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,10 +18,12 @@
# USA.
#
# Version: $Id$
import getopt, sys, logging
import getopt
import sys
import logging
from gnuviechadmin.exceptions import GnuviechadminError
class CliCommand:
"""Base class for command line interface.
@ -65,17 +66,17 @@ Common options:
%(option)s
%(mandatory)s %(optiondesc)s
""" % { 'called' : sys.argv[0],
'command' : self.name,
'description' : self.description,
'option' : '-v, --verbose',
'optiondesc' : 'verbose operation',
'mandatory' : " "}
""" % {'called': sys.argv[0],
'command': self.name,
'description': self.description,
'option': '-v, --verbose',
'optiondesc': 'verbose operation',
'mandatory': " "}
for commandname in self._optionmap.keys():
cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % {
'called' : sys.argv[0],
'command' : self.name,
'subcommand' : commandname}
'called': sys.argv[0],
'command': self.name,
'subcommand': commandname}
desc = """
%s
""" % (self._optionmap[commandname][0])
@ -97,9 +98,9 @@ Common options:
if not mandatory:
cmd = cmd + "]"
descmap = {
'option' : ", ".join(pairs),
'optiondesc' : optiondesc,
'mandatory' : ' '}
'option': ", ".join(pairs),
'optiondesc': optiondesc,
'mandatory': ' '}
if mandatory:
descmap['mandatory'] = '*'
desc = desc + """ %(option)s

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,7 +18,6 @@
# USA.
#
# Version: $Id$
"""This is the gnuviechadmin.cli package.
This package provides modules for the command line interface of the

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,8 +18,9 @@
# USA.
#
# Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class ClientCli(CliCommand.CliCommand):
"""Command line interface command for client management."""
@ -28,37 +28,36 @@ class ClientCli(CliCommand.CliCommand):
name = "client"
description = "manage clients"
_optionmap = {
'create' : ("creates a new client",
[(["-f", "--firstname"], "firstname",
"the client's first name", True),
(["-l", "--lastname"], "lastname",
"the client's last name", True),
(["-t", "--title"], "title",
"the client's title", False),
(["-a", "--address"], "address1",
"the address of the client", True),
(["--address2"], "address2",
"second line of the client's address", False),
(["-z", "--zip"], "zip",
"the zipcode of the client's address", True),
(["-c", "--city"], "city",
"the city of the client's address", True),
(["--country"], "country",
"the client's country", False),
(["-e", "--email"], "email",
"the client's email address", True),
(["-p", "--phone"], "phone",
"the client's phone number", True),
(["-m", "--mobile"], "mobile",
"the client's mobile phone number", False),
(["-x", "--fax"], "fax",
"the client's fax number", False)]),
'list' : ("lists existing clients",
[]),
'delete' : ("deletes the specified client if it has no dependent data",
[(["-c", "--clientid"], "clientid",
"the client id", True)])}
'create': ("creates a new client",
[(["-f", "--firstname"], "firstname",
"the client's first name", True),
(["-l", "--lastname"], "lastname",
"the client's last name", True),
(["-t", "--title"], "title",
"the client's title", False),
(["-a", "--address"], "address1",
"the address of the client", True),
(["--address2"], "address2",
"second line of the client's address", False),
(["-z", "--zip"], "zip",
"the zipcode of the client's address", True),
(["-c", "--city"], "city",
"the city of the client's address", True),
(["--country"], "country",
"the client's country", False),
(["-e", "--email"], "email",
"the client's email address", True),
(["-p", "--phone"], "phone",
"the client's phone number", True),
(["-m", "--mobile"], "mobile",
"the client's mobile phone number", False),
(["-x", "--fax"], "fax",
"the client's fax number", False)]),
'list': ("lists existing clients", []),
'delete': ("deletes the specified client if it has no dependent data",
[(["-c", "--clientid"], "clientid",
"the client id", True)])}
def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand,
str(self._data))

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,8 +18,9 @@
# USA.
#
# Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class DomainCli(CliCommand.CliCommand):
"""Command line interface command for domain management."""
@ -28,20 +28,19 @@ class DomainCli(CliCommand.CliCommand):
name = "domain"
description = "manage domains"
_optionmap = {
'create' : ("creates a new domain",
[(["-n", "--name"], "name",
"the domain name", True),
(["-t", "--type"], "type",
"domain type m for master or s for slave", False),
(["-m", "--master"], "master",
"master server for slave domains", False),
(["-s", "--sysuserid"], "sysuserid",
"system user id", True)]),
'list' : ("lists existing domains",
[]),
'delete' : ("delete a domain",
[(["-d", "--domainid"], "domainid",
"the domain id", True)])}
'create': ("creates a new domain",
[(["-n", "--name"], "name",
"the domain name", True),
(["-t", "--type"], "type",
"domain type m for master or s for slave", False),
(["-m", "--master"], "master",
"master server for slave domains", False),
(["-s", "--sysuserid"], "sysuserid",
"system user id", True)]),
'list': ("lists existing domains", []),
'delete': ("delete a domain",
[(["-d", "--domainid"], "domainid",
"the domain id", True)])}
def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand,

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,8 +18,9 @@
# USA.
#
# Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class RecordCli(CliCommand.CliCommand):
"""Command line interface command for DNS record management."""
@ -28,25 +28,25 @@ class RecordCli(CliCommand.CliCommand):
name = "record"
description = "manage DNS records"
_optionmap = {
'create' : ("creates a new record",
[(["-n", "--name"], "name",
"the record name", True),
(["-t", "--type"], "type",
"record type", True),
(["-c", "--content"], "content",
"record content", True),
(["-p", "--prio"], "prio",
"MX record priority", False),
(["--ttl"], "ttl",
"time to live", False),
(["-d", "--domainid"], "domainid",
"domain id", True)]),
'list' : ("lists existing records",
[(["-d", "--domainid"], "domainid",
"domain id", False)]),
'delete' : ("delete a record",
[(["-r", "--recordid"], "recordid",
"the record id", True)])}
'create': ("creates a new record",
[(["-n", "--name"], "name",
"the record name", True),
(["-t", "--type"], "type",
"record type", True),
(["-c", "--content"], "content",
"record content", True),
(["-p", "--prio"], "prio",
"MX record priority", False),
(["--ttl"], "ttl",
"time to live", False),
(["-d", "--domainid"], "domainid",
"domain id", True)]),
'list': ("lists existing records",
[(["-d", "--domainid"], "domainid",
"domain id", False)]),
'delete': ("delete a record",
[(["-r", "--recordid"], "recordid",
"the record id", True)])}
def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand,

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,33 +18,33 @@
# USA.
#
# Version: $Id$
import CliCommand
import sys
import CliCommand, sys
class SysuserCli(CliCommand.CliCommand):
"""Command line interface command for system user managament."""
name = "sysuser"
name = "sysuser"
description = "manage system users"
_optionmap = {
"create" : ("create a new system user with the given options.",
[(["-n", "--username"], "username",
"the system user name", False),
(["-t", "--usertype"], "usertype",
"the numeric user type", False),
(["-h", "--home"], "home",
"the home directory", False),
(["-s", "--shell"], "shell",
"true if the user should get shell access", False),
(["-p", "--password"], "clearpass",
"the password for the user", False),
(["-c", "--clientid"], "clientid",
"the client id", True)]),
"list" : ("list existing system users.",
[]),
"delete" : ("delete a system user.",
[(["-s", "--sysuserid"], "sysuserid",
"the system user id", True)])}
_optionmap = {
"create": ("create a new system user with the given options.",
[(["-n", "--username"], "username",
"the system user name", False),
(["-t", "--usertype"], "usertype",
"the numeric user type", False),
(["-h", "--home"], "home",
"the home directory", False),
(["-s", "--shell"], "shell",
"true if the user should get shell access", False),
(["-p", "--password"], "clearpass",
"the password for the user", False),
(["-c", "--clientid"], "clientid",
"the client id", True)]),
"list": ("list existing system users.", []),
"delete": ("delete a system user.",
[(["-s", "--sysuserid"], "sysuserid",
"the system user id", True)])}
def _execute(self, subcommand):
self.logger.debug("execute %s with data %s", subcommand,

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -19,26 +18,30 @@
# USA.
#
# Version: $Id$
"""This file defines the gnuviechadmin specific exception types."""
class GnuviechadminError(Exception):
"""This is the base class for domain specific exceptions of
Gnuviechadmin."""
pass
class MissingFieldsError(GnuviechadminError):
"""This exception should be raised when a required field of a data
class is missing."""
def __init__(self, missingfields):
self.missing = missingfields
def __str__(self):
return "the fields %s are missing." % (repr(self.missing))
class CreationFailedError(GnuviechadminError):
"""This exception should be raised if a business object could not
be created."""
def __init__(self, classname, cause = None):
self.classname = classname
self.cause = cause
@ -49,9 +52,11 @@ class CreationFailedError(GnuviechadminError):
msg += " The reason is %s." % (str(self.cause))
return msg
class DeleteFailedError(GnuviechadminError):
"""This exception should be raise if a business object coild not
be deleted."""
def __init__(self, classname, cause = None):
self.classname = classname
self.cause = cause
@ -62,9 +67,11 @@ class DeleteFailedError(GnuviechadminError):
msg += " The reason is %s." % (str(self.cause))
return msg
class ValidationFailedError(GnuviechadminError):
"""This exception should be raised if the validation of a business
object failed."""
def __init__(self, instance, cause = None):
self.instance = instance
self.cause = cause
@ -75,9 +82,11 @@ class ValidationFailedError(GnuviechadminError):
msg += " The reason is %s." % (str(self.cause))
return msg
class CannotDeleteError(GnuviechadminError):
"""This exception should be raised if an entity cannot be deleted
because of some unmatched precondition."""
def __init__(self, instance, cause = None):
self.instance = instance
self.cause = cause

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -22,10 +21,13 @@
"""Tools for handling user and group information."""
import pwd, grp
import pwd
import grp
class PasswdUser(object):
"""This class represents users in the user database."""
def __init__(self, username, pw, uid, gid, gecos, home, shell):
"""Create a new PasswdUser."""
self.username = username
@ -45,8 +47,10 @@ class PasswdUser(object):
self.home,
self.shell)
class PasswdGroup(object):
"""This class represents lines in the groups database."""
def __init__(self, groupname, pw, gid, members):
"""Create a new PasswdGroup."""
self.groupname = groupname
@ -60,18 +64,22 @@ class PasswdGroup(object):
self.gid,
",".join(self.members))
def parse_groups():
"""Parses all available groups to PasswdGroup instances."""
return [PasswdGroup(*arr) for arr in grp.getgrall()]
def parse_users():
"""Parses all available users to PasswdUser instances."""
return [PasswdUser(*arr) for arr in pwd.getpwall()]
def find_user_by_prefix(prefix):
"""Finds all user entries with the given prefix."""
"""Finds all user entries with the given prefix."""
return [user for user in parse_users() if user.username.startswith(prefix)]
def get_user_by_id(uid):
"""Gets the user with the given user id."""
users = [user for user in parse_users() if user.uid == uid]
@ -79,6 +87,7 @@ def get_user_by_id(uid):
return users[0]
return None
def get_group_by_id(gid):
"""Gets the group with the given group id."""
groups = [group for group in parse_groups() if group.gid == gid]
@ -86,6 +95,7 @@ def get_group_by_id(gid):
return groups[0]
return None
def get_next_uid(lowerboundary = 10000, upperboundary = 65536):
"""Gets the first available user id in the given range.
@ -98,16 +108,19 @@ def get_next_uid(lowerboundary = 10000, upperboundary = 65536):
"""
for uid in range(lowerboundary, upperboundary):
try:
user = pwd.getpwuid(uid)
except KeyError:
return uid
raise Exception("no free uid found in range %d to %d", lowerboundary, upperboundary)
try:
user = pwd.getpwuid(uid)
except KeyError:
return uid
raise Exception("no free uid found in range %d to %d",
lowerboundary, upperboundary)
def get_max_uid(boundary = 65536):
"""Gets the highest uid value."""
return max([user.uid for user in parse_users() if user.uid <= boundary])
def get_max_gid(boundary = 65536):
"""Gets the highest gid value."""
return max([group.gid for group in parse_groups() \
@ -119,4 +132,3 @@ if __name__ == "__main__":
print "User with max UID is %s" % (get_user_by_id(get_max_uid(40000)))
print "Group with max GID is %s" % (get_group_by_id(get_max_gid(40000)))
print "First free UID is %s" % (get_next_uid(10000, 40000))

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -33,6 +32,7 @@ from pyme.constants.sig import mode
from gnuviechadmin.backend.settings import config
def send_mail(subject, text):
"""Send a signed and possibly encrypted mail.
@ -56,33 +56,33 @@ def send_mail(subject, text):
rcpt = config.get('common', 'mailto')
c.signers_clear()
for sigkey in [x for x in c.op_keylist_all(signer, 1)]:
if sigkey.can_sign:
c.signers_add(sigkey)
if not c.signers_enum(0):
raise Exception("No secret keys for signing available for %s." % (
signer))
if sigkey.can_sign:
c.signers_add(sigkey)
if not c.signers_enum(0):
raise Exception("No secret keys for signing available for %s." % (
signer))
keylist = []
for key in c.op_keylist_all(rcpt, 0):
valid = 0
subkey = key.subkeys
while subkey:
keyid = subkey.keyid
if keyid == None:
break
can_encrypt = subkey.can_encrypt
valid += can_encrypt
subkey = subkey.next
if valid:
keylist.append(key)
valid = 0
subkey = key.subkeys
while subkey:
keyid = subkey.keyid
if keyid == None:
break
can_encrypt = subkey.can_encrypt
valid += can_encrypt
subkey = subkey.next
if valid:
keylist.append(key)
if keylist:
c.op_encrypt_sign(keylist, 1, plain, cipher)
c.op_encrypt_sign(keylist, 1, plain, cipher)
else:
c.op_sign(plain, cipher, mode.CLEAR)
cipher.seek(0,0)
c.op_sign(plain, cipher, mode.CLEAR)
cipher.seek(0, 0)
msg = MIMEText(cipher.read())
if keylist:
msg.set_param("x-action", "pgp-encrypted")
msg.set_param("x-action", "pgp-encrypted")
msg['Subject'] = subject
msg['From'] = signer
msg['To'] = rcpt

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -21,7 +20,9 @@
# Version: $Id$
"""This module provides some functions for password handling."""
import crypt, crack, random
import crypt
import crack
import random
_pwchars = []
for _pair in (('0', '9'), ('A', 'Z'), ('a', 'z')):
@ -30,6 +31,7 @@ _saltchars = [_char for _char in _pwchars]
for _char in "-+/*_@":
_pwchars.append(ord(_char))
def generatepassword(minlength = 8, maxlength = 12):
"""Generates a new random password with a given length.
@ -44,6 +46,7 @@ def generatepassword(minlength = 8, maxlength = 12):
random.sample(_pwchars,
random.randint(minlength, maxlength))])
def checkpassword(password):
"""Checks the password with cracklib.
@ -58,7 +61,8 @@ def checkpassword(password):
except ValueError, ve:
print "Weak password:", ve
return None
def md5_crypt_password(password):
"""Hashes the given password with MD5 and a random salt value.
@ -71,6 +75,7 @@ def md5_crypt_password(password):
random.sample(_saltchars, 8)])
return crypt.crypt(password, '$1$' + salt)
def get_pw_tuple(password = None):
"""Gets a valid (password, hashvalue) tuple.
@ -82,3 +87,6 @@ def get_pw_tuple(password = None):
while password == None or checkpassword(password) == None:
password = generatepassword()
return (password, md5_crypt_password(password))
# TODO: implement a is_password_valid(hash, password) function

31
gnuviechadmin/util/stmtcreator.py Normal file → Executable file
View File

@ -1,4 +1,4 @@
# -*- python -*-
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -24,16 +24,23 @@
creation."""
if __name__ == '__main__':
from passwordutils import get_pw_tuple
import sys
from passwordutils import get_pw_tuple
import sys
for line in sys.stdin.readlines():
parts = line.split()
if len(parts) < 4:
raise ValueError("""lines must consist of the elements:
for line in sys.stdin.readlines():
parts = line.split()
if len(parts) < 4:
raise ValueError("""lines must consist of the elements:
email@domain username uid domainid""")
(email, domain) = parts[0].split("@")
username = parts[1][0:5]
pwtuple = get_pw_tuple()
print "INSERT INTO mailpassword (id, clearpass, cryptpass, uid, gid, home, spamcheck) VALUES ('%s', '%s', '%s', %d, %d, '/home/mail/%s/%s', 'false');" % (parts[1], pwtuple[0], pwtuple[1], int(parts[2]), 119, username, parts[1])
print "INSERT INTO mailaddress (domainid, email, target) VALUES (%d, '%s', '%s');" % (int(parts[3]), email, parts[1])
(email, domain) = parts[0].split("@")
username = parts[1][0:5]
pwtuple = get_pw_tuple()
print "INSERT INTO mailpassword " + \
"(id, clearpass, cryptpass, uid, gid, home, spamcheck) " + \
"VALUES " + \
"('%s', '%s', '%s', %d, %d, '/home/mail/%s/%s', 'false');" % (
parts[1], pwtuple[0], pwtuple[1], int(parts[2]), 119,
username, parts[1])
print "INSERT INTO mailaddress (domainid, email, target) " + \
"VALUES (%d, '%s', '%s');" % (
int(parts[3]), email, parts[1])

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 by Jan Dittberner.
@ -19,12 +18,12 @@
# USA.
#
# Version: $Id$
"""This file defines a facade for exporting gnuviechadmin
functionality via XMLRPC."""
from gnuviechadmin.xmlrpc.users import GVAUsers
class XMLRPCFacade(GVAUsers):
"""This class provides access to selected gnuviechadmin
functionality for use via XMLRPC."""

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2008 by Jan Dittberner.
@ -19,7 +18,6 @@
# USA.
#
# Version: $Id$
"""This is the gnuviechadmin.xmlrpc package.
This package provides modules for the XMLRPC interface of the

View File

@ -1,20 +1,47 @@
# -*- 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 file provides a authkit.users.Users implementation and several
UserProviders for authenticating different user types and enabling
password change functions."""
from authkit.users import Users, AuthKitNoSuchUserError
import logging
log = logging.getLogger(__name__)
class UserProvider(Users):
"""A base class for user providers."""
def _get_user(self, username, password, role):
return {
'username' : username,
'group' : None,
'password' : password,
'roles' : [role]
}
'username': username,
'group': None,
'password': password,
'roles': [role]}
class ClientUserProvider(UserProvider):
"""A UserProvider implementation class for clients."""
def user(self, username):
print 'checking %s' % username
if username == 'dummy':
@ -24,23 +51,34 @@ class ClientUserProvider(UserProvider):
def list_roles(self):
return ['client']
class MailuserUserProvider(UserProvider):
"""A UserProvider implementation class for mail users."""
def user(self, username):
raise AuthKitNoSuchUserError()
def list_roles(self):
return ['mailuser']
class SysuserUserProvider(UserProvider):
"""A UserProvider implementation class for system users."""
def user(self, username):
raise AuthKitNoSuchUserError()
def list_roles(self):
return ['sysuser']
class GVAUsers(Users):
"""This class provides an implementation of authkit.users.Users
which dispatches several methods to configured UserProvider
implementations."""
def __init__(self, data, userproviders = [], encrypt = None):
"""Initialize the GVAXMLRPCUsers instance."""
"""Initialize the GVAUsers instance."""
Users.__init__(self, data, encrypt)
self.userproviders = [prov(self.data) for prov in userproviders]
@ -65,16 +103,16 @@ class GVAUsers(Users):
def user(self, username):
"""Returns a dictionary in the following format:
.. code-block :: Python
{
'username': username,
'group': group,
'password': password,
'roles': [role1,role2,role3... etc]
}
The role names are ordered alphabetically
Raises an exception if the user doesn't exist."""
for prov in self.userproviders:

View File

@ -1,4 +1,3 @@
# -*- python -*-
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
@ -36,7 +35,7 @@ setup(
setup_requires = [],
include_package_data = True,
exclude_package_data = { '' : ['gva.cfg'] },
exclude_package_data = {'': ['gva.cfg']},
author = 'Jan Dittberner',
author_email = 'jan@dittberner.info',
@ -44,7 +43,7 @@ setup(
long_description = """this is a suite of tools for administering a server
it contains tools for maintaining e.g. clients, domains, users, mail
accounts""",
license = 'GPL',
license = 'GPL',
keywords = 'administration backend frontend',
url = 'http://www.gnuviech-server.de/projects/gnuviechadmin',
)

View File

@ -1,4 +1,5 @@
#!/usr/bin/python
from migrate.versioning.shell import main
main(url='postgres://jan:heyyou97@localhost:5432/jan',repository='ormaptest_repo')
main(url='postgres://jan:heyyou97@localhost:5432/jan',
repository='ormaptest_repo')

View File

@ -1,26 +1,47 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# -*- 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$
from sqlalchemy import *
meta = BoundMetaData('postgres://jan:heyyou97@localhost:5432/jan')
domains_table = Table('domains', meta, autoload=True)
records_table = Table('records', meta, autoload=True)
class Domain(object):
def __repr__(self):
return "%s(%r,%r)" % (
self.__class__.__name__, self.id, self.name)
class Record(object):
def __repr__(self):
return "%s(%r,%r,%r)" % (
self.__class__.__name__, self.id, self.domain_id, self.domain)
recordmapper = mapper(Record, records_table)
domainmapper = mapper(Domain, domains_table, properties = {
'records': relation(Record, backref='domain')
})
'records': relation(Record, backref='domain')})
session = create_session()
query = session.query(Domain)

View File

@ -7,8 +7,10 @@ account = Table('account', meta,
Column('login', String(40)),
Column('passwd', String(40)))
def upgrade():
account.create()
def downgrade():
account.drop()

View File

@ -4,8 +4,10 @@ from migrate import *
meta = BoundMetaData(migrate_engine)
account = Table('account', meta)
def upgrade():
account.drop()
def downgrade():
account.create()

View File

@ -15,8 +15,7 @@ domains = Table('domains', meta,
Column('type', String(6), nullable=False),
Column('notified_serial', Integer),
Column('account', String(40)),
UniqueConstraint('name', name='name_index')
)
UniqueConstraint('name', name='name_index'))
records = Table('records', meta,
Column('id', Integer, primary_key=True),
@ -28,17 +27,18 @@ records = Table('records', meta,
Column('prio', Integer),
Column('change_date', Integer),
ForeignKeyConstraint(['domain_id'], ['domains.id'],
ondelete='CASCADE', name='domain_exists')
)
ondelete='CASCADE', name='domain_exists'))
Index('domain_id', records.c.domain_id)
Index('nametype_index', records.c.name, records.c.type)
Index('rec_name_index', records.c.name)
def upgrade():
supermasters.create()
domains.create()
records.create()
def downgrade():
records.drop()
domains.drop()

View File

@ -1,74 +1,93 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2007 Jan Dittberner
# $Id$
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
import getopt, sys
# 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$
import getopt
import sys
from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --firstname=<firstname> --lastname=<lastname> \
--address1=<address1> --town=<town> --zipcode=<zipcode> \
[--address2=<address2>] [--country=<country>] [--state=<state>] \
[--active=true|false] [--phone=<phone>] [--mobile=<mobile>]
- adds a new client
""" % {'process': sys.argv[0]}
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --firstname=<firstname> --lastname=<lastname> \
--address1=<address1> --town=<town> --zipcode=<zipcode> \
[--address2=<address2>] [--country=<country>] [--state=<state>] \
[--active=true|false] [--phone=<phone>] [--mobile=<mobile>]
- adds a new client
""" % {'process': sys.argv[0]}
if __name__ == "__main__":
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help',
'firstname=', 'lastname=', 'address1=',
'town=', 'zipcode=', 'address2=',
'country=', 'state=', 'active=',
'phone=', 'mobile='])
except getopt.GetoptError:
usage()
sys.exit(1)
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help',
'firstname=', 'lastname=',
'address1=',
'town=', 'zipcode=', 'address2=',
'country=', 'state=', 'active=',
'phone=', 'mobile='])
except getopt.GetoptError:
usage()
sys.exit(1)
if (not options or
dict(options).has_key('-h') or
dict(options).has_key('--help') or
not dict(options).has_key('--firstname') or
not dict(options).has_key('--lastname') or
not dict(options).has_key('--address1') or
not dict(options).has_key('--town') or
not dict(options).has_key('--zipcode') or
not dict(options)['--firstname'].strip() or
not dict(options)['--lastname'].strip() or
not dict(options)['--address1'].strip() or
not dict(options)['--town'].strip() or
not dict(options)['--zipcode'].strip()):
usage()
sys.exit(1)
if (not options or
'-h' in dict(options) or
'--help' in dict(options) or
not '--firstname' in dict(options) or
not '--lastname' in dict(options) or
not '--address1' in dict(options) or
not '--town' in dict(options) or
not '--zipcode' in dict(options) or
not dict(options)['--firstname'].strip() or
not dict(options)['--lastname'].strip() or
not dict(options)['--address1'].strip() or
not dict(options)['--town'].strip() or
not dict(options)['--zipcode'].strip()):
usage()
sys.exit(1)
po = dict(options)
for key in po.keys():
po[key] = po[key].strip()
client = Client()
client.firstname = po['--firstname']
client.lastname = po['--lastname']
client.address1 = po['--address1']
client.town = po['--town']
client.zipcode = po['--zipcode']
if po.has_key('--active'):
client.active = (po['--active'] == 'true')
else:
client.active = True
if po.has_key('--address2') and po['--address2']:
client.address2 = po['--address2']
if po.has_key('--country') and po['--country']:
client.country = po['--country']
if po.has_key('--state') and po['--state']:
client.state = po['--state']
if po.has_key('--phone') and po['--phone']:
client.phone = po['--phone']
if po.has_key('--mobile') and po['--mobile']:
client.mobile = po['--mobile']
session.save(client)
session.flush()
po = dict(options)
for key in po.keys():
po[key] = po[key].strip()
client = Client()
client.firstname = po['--firstname']
client.lastname = po['--lastname']
client.address1 = po['--address1']
client.town = po['--town']
client.zipcode = po['--zipcode']
if '--active' in po:
client.active = (po['--active'] == 'true')
else:
client.active = True
if '--address2' in po and po['--address2']:
client.address2 = po['--address2']
if '--country' in po and po['--country']:
client.country = po['--country']
if '--state' in po and po['--state']:
client.state = po['--state']
if '--phone' in po and po['--phone']:
client.phone = po['--phone']
if '--mobile' in po and po['--mobile']:
client.mobile = po['--mobile']
session.save(client)
session.flush()

View File

@ -1,59 +1,77 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2007 Jan Dittberner
# $Id$
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
import getopt, sys
# 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$
import getopt
import sys
from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> --sysuser=<sysuser> --type=MASTER|SLAVE \
[[--ns=<nameserver>] [--mx=<mxserver[,prio]>] [--a=<ipaddress>] ...]
- adds a new domain
""" % {'process': sys.argv[0]}
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> --sysuser=<sysuser> --type=MASTER|SLAVE \
[[--ns=<nameserver>] [--mx=<mxserver[,prio]>] [--a=<ipaddress>] ...]
- adds a new domain
""" % {'process': sys.argv[0]}
if __name__ == "__main__":
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help',
'domain=', 'sysuser=',
'type=', 'ns=', 'mx=', 'a='])
except getopt.GetoptError:
usage()
sys.exit(1)
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help',
'domain=', 'sysuser=',
'type=', 'ns=', 'mx=', 'a='])
except getopt.GetoptError:
usage()
sys.exit(1)
if (not options or
dict(options).has_key('-h') or
dict(options).has_key('--help') or
not dict(options).has_key('--domain') or
not dict(options).has_key('--sysuser') or
not dict(options)['--sysuser'].strip() or
not dict(options)['--domain'].strip()):
usage()
sys.exit(1)
if (not options or
'-h' in dict(options) or
'--help' in dict(options) or
not '--domain' in dict(options) or
not '--sysuser' in dict(options) or
not dict(options)['--sysuser'].strip() or
not dict(options)['--domain'].strip()):
usage()
sys.exit(1)
po = {}
for (key, value) in options:
if po.has_key(key):
po[key].append(value.strip())
else:
po[key] = [value.strip()]
po = {}
for (key, value) in options:
if key in po:
po[key].append(value.strip())
else:
po[key] = [value.strip()]
# fetch the sysuser
query = session.query(SysUser)
sysuser = query.get_by(name = po['--sysuser'][0])
if not sysuser:
print "Invalid system user"
allsysusers = query.get_by(name = '*')
if allsysusers:
print "Valid system users are:\n%s" % ("\n".join(allsysusers))
else:
print "No system users defined yet."
sys.exit(1)
# fetch the sysuser
query = session.query(SysUser)
sysuser = query.get_by(name = po['--sysuser'][0])
if not sysuser:
print "Invalid system user"
allsysusers = query.get_by(name = '*')
if allsysusers:
print "Valid system users are:\n%s" % ("\n".join(allsysusers))
else:
print "No system users defined yet."
sys.exit(1)
print sysuser.domains
print sysuser.domains

View File

@ -1,45 +1,64 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2007 Jan Dittberner
# $Id$
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
import getopt, sys
# 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$
import getopt
import sys
from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> [--password=<password>]
- adds a new pop user for the given domain
- if the optional password is ommitted a generated one is used
- the password is checked using cracklib
- if the password is too weak a generated one is used
""" % {'process': sys.argv[0]}
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --domain=<domain> [--password=<password>]
- adds a new pop user for the given domain
- if the optional password is ommitted a generated one is used
- the password is checked using cracklib
- if the password is too weak a generated one is used
""" % {'process': sys.argv[0]}
if __name__ == "__main__":
try:
(options, args) = getopt.getopt(sys.argv[1:], "h", ['help', 'password=', 'domain='])
except getopt.GetoptError:
usage()
sys.exit(1)
if (not options or
dict(options).has_key('-h') or
dict(options).has_key('--help') or
not dict(options).has_key('--domain') or
not dict(options)['--domain'].strip()):
usage()
sys.exit(1)
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help', 'password=', 'domain='])
except getopt.GetoptError:
usage()
sys.exit(1)
# specify the domain
query = session.query(Domain)
domain = query.get_by(name = dict(options)['--domain'].strip())
if not domain:
print "Invalid Domain"
print "valid domains are:\n%s" % ("\n".join(query.get()))
sys.exit(1)
print domain.popaccounts
if (not options or
'-h' in dict(options) or
'--help' in dict(options) or
not '--domain' in dict(options) or
not dict(options)['--domain'].strip()):
usage()
sys.exit(1)
# specify the domain
query = session.query(Domain)
domain = query.get_by(name = dict(options)['--domain'].strip())
if not domain:
print "Invalid Domain"
print "valid domains are:\n%s" % ("\n".join(query.get()))
sys.exit(1)
print domain.popaccounts

View File

@ -1,53 +1,72 @@
#!/usr/bin/env python
#
# Copyright (c) 2007 Jan Dittberner
# $Id$
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
import getopt, sys
# 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$
import getopt
import sys
from gnuviechadmin.dblayer import *
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --type=admin|reseller|client --clientid=<clientid> \
[--name=<name>] [--home=<home>] [--shell=<shell>] [--password] \
[--sysuid=<uid>]
- adds a new system user
""" % {'process': sys.argv[0]}
def usage():
print """Usage information:
=====================
%(process)s -h|--help
- prints this help text
%(process)s --type=admin|reseller|client --clientid=<clientid> \
[--name=<name>] [--home=<home>] [--shell=<shell>] [--password] \
[--sysuid=<uid>]
- adds a new system user
""" % {'process': sys.argv[0]}
if __name__ == "__main__":
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help',
'type=', 'clientid=', 'name=', 'home=',
'shell=', 'password=', 'sysuid='])
except getopt.GetoptError:
usage()
sys.exit(1)
try:
(options, args) = getopt.getopt(sys.argv[1:], "h",
['help', 'type=', 'clientid=',
'name=', 'home=', 'shell=',
'password=', 'sysuid='])
except getopt.GetoptError:
usage()
sys.exit(1)
if (not options or
dict(options).has_key('-h') or
dict(options).has_key('--help') or
not dict(options).has_key('--type') or
not dict(options).has_key('--clientid') or
not dict(options)['--type'].strip() or
not dict(options)['--clientid'].strip() or
not dict(options)['--type'].strip() in ('admin', 'reseller', 'client')):
usage()
sys.exit(1)
if (not options or
'-h' in dict(options) or
'--help' in dict(options) or
not '--type' in dict(options) or
not '--clientid' in dict(options) or
not dict(options)['--type'].strip() or
not dict(options)['--clientid'].strip() or
not dict(options)['--type'].strip() in ('admin', 'reseller',
'client')):
usage()
sys.exit(1)
query = session.query(Client)
client = query.get_by(clientid = dict(options)['--clientid'].strip())
if not client:
print "Invalid client"
query = session.query(Client)
client = query.get_by(clientid = dict(options)['--clientid'].strip())
if not client:
print "Invalid client"
allclients = query.select()
if allclients:
print "Valid clients are:\n- %s" % "\n- ".join([str(client) for client in allclients])
print "Valid clients are:\n- %s" % "\n- ".join(
[str(client) for client in allclients])
else:
print "No clients defined yet."
sys.exit(1)
print client.sysusers
print client.sysusers

View File

@ -6,7 +6,7 @@ meta = BoundMetaData(migrate_engine)
domains = Table('domains', meta, autoload = True)
mailalias = Table(
'mailalias', meta,
Column('mailaliasid', Integer, primary_key = True),
Column('mailaliasid', Integer, primary_key = True),
Column('domainid', Integer, ForeignKey('domains.id'), nullable = False),
Column('email', String(255), nullable = False),
Column('target', TEXT, nullable = False),
@ -24,10 +24,12 @@ mailpassword = Table(
Column('spamcheck', Boolean, default = False),
Column('sajunkscore', Integer))
def upgrade():
mailalias.create()
mailpassword.create()
def downgrade():
mailpassword.drop()
mailalias.drop()

View File

@ -31,10 +31,12 @@ sysuser_table = Table(
Column('md5pass', String(34)),
Column('sysuid', Integer))
def upgrade():
client_table.create()
sysuser_table.create()
def downgrade():
sysuser_table.drop()
client_table.drop()

View File

@ -9,9 +9,11 @@ sysuidrefcol = Column('sysuserid', Integer,
ForeignKey('sysuser.sysuserid'),
nullable = False)
def upgrade():
sysuidrefcol.create(domains)
def downgrade():
col = domains.c.sysuserid
col.drop()

View File

@ -1,4 +1,5 @@
#!/usr/bin/python
from migrate.versioning.shell import main
main(url='postgres://jan:heyyou97@localhost:5432/testdb',repository='gnuviechadmin')
main(url='postgres://jan:heyyou97@localhost:5432/testdb',
repository='gnuviechadmin')

View File

@ -1,3 +1,23 @@
# -*- 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$
from sqlalchemy import *
from entities import *

View File

@ -1,4 +1,27 @@
# -*- 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$
class Client(object):
def __repr__(self):
return "%s(clientid=%s,firstname=%s,lastname=%s)" % \
(self.__class__.__name__,
@ -6,7 +29,9 @@ class Client(object):
self.firstname,
self.lastname)
class PopAccount(object):
def __repr__(self):
return "%s(%s,%d,%d,%d,%s,%s,%s)" % \
(self.__class__.__name__,
@ -18,7 +43,9 @@ class PopAccount(object):
self.cryptpass,
self.clearpass)
class SysUser(object):
def __repr__(self):
return "%s(%d,%s,%d,%s,%s,%s,%d,%d,%s,%d)" % \
(self.__class__.__name__,
@ -33,7 +60,9 @@ class SysUser(object):
self.md5pass,
self.sysuid)
class Domain(object):
def __repr__(self):
return "%s(%d,%s,%s,%s,%s,%s,%s)" % \
(self.__class__.__name__,