1
0
Fork 0

- restructured

- implementation of client and sysuser cli
- backend for client, sysuser, domain and record
- unified cli binary gva


git-svn-id: file:///home/www/usr01/svn/gnuviechadmin/gnuviech.info/gnuviechadmin/trunk@226 a67ec6bc-e5d5-0310-a910-815c51eb3124
This commit is contained in:
Jan Dittberner 2007-07-02 09:14:47 +00:00
parent ee36146629
commit 926acaddfa
19 changed files with 1010 additions and 345 deletions

View file

@ -0,0 +1,83 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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$
import ConfigParser, os
from subprocess import *
from sqlalchemy import *
from gnuviechadmin.exceptions import *
class BackendEntity(object):
"""This is the abstract base class for all backend entity classes."""
def __init__(self, verbose = False):
self.verbose = verbose
self.config = ConfigParser.ConfigParser()
self.config.readfp(open('gnuviechadmin/defaults.cfg'))
self.config.read(['gnuviechadmin/gva.cfg',
os.path.expanduser('~/.gva.cfg')])
def __repr__(self):
if self.verbose:
cols = [col for col in \
object_mapper(self).local_table.columns.keys()]
format = "%(class)s:"
format = format + ", ".join([col + "=%(" + col + ")s" for col in \
cols])
data = {'class' : self.__class__.__name__}
else:
cols = self._shortkeys
format = ",".join("%(" + col + ")s" for col in cols)
data = {}
data.update(dict([(col, self.__getattribute__(col)) for col in cols]))
return format % data
def sucommand(self, cmdline, pipedata = None):
"""Executes a command as root using the configured suwrapper
command. If a pipe is specified it is used as stdin of the
subprocess."""
suwrapper = self.config.get('common', 'suwrapper')
toexec = "%s %s" % (suwrapper, cmdline)
if pipedata:
p = Popen(toexec, shell = True, stdin=PIPE)
pipe = p.stdin
print >>pipe, pipedata
pipe.close()
sts = os.waitpid(p.pid, 0)
if self.verbose:
print "%s|%s: %d" % (pipedata, toexec, sts[1])
else:
p = Popen(toexec, shell = True)
sts = os.waitpid(p.pid, 0)
if self.verbose:
print "%s: %s" % (toexec, sts[1])
return sts[1]
def validate(self):
"""Validates whether all mandatory fields of the entity have
values."""
missingfields = []
for key in [col.name for col in \
object_mapper(self).local_table.columns \
if not col.primary_key and not col.nullable]:
if self.__getattribute__(key) is None:
missingfields.append(key)
if missingfields:
raise MissingFieldsError(missingfields)

View file

@ -0,0 +1,69 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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 gnuviechadmin.exceptions import *
from BackendEntity import *
class BackendEntityHandler(object):
def __init__(self, entityclass, verbose = False):
self.entityclass = entityclass
self.verbose = verbose
def create(self, **kwargs):
try:
entity = self.entityclass(self.verbose, **kwargs)
sess = create_session()
sess.save(entity)
sess.flush()
try:
entity.create_hook()
except:
sess.delete(entity)
sess.flush()
raise
except Exception, e:
raise CreationFailedError(self.entityclass.__name__, e)
def fetchall(self):
"""Fetches all entities of the managed entity type."""
session = create_session()
query = session.query(self.entityclass)
allentities = query.select()
for entity in allentities:
BackendEntity.__init__(entity, self.verbose)
return allentities
def delete(self, pkvalue):
"""Deletes the entity of the managed entity type that has the
specified primary key value."""
try:
sess = create_session()
entity = sess.query(self.entityclass).get(pkvalue)
if entity:
BackendEntity.__init__(entity, self.verbose)
if self.verbose:
print "delete %s" % (str(entity))
entity.delete_hook()
sess.delete(entity)
sess.flush()
except Exception, e:
raise DeleteFailedError(self.entityclass.__name__, e)

View file

@ -0,0 +1,25 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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 is the gnuviechadmin.backend package.
The package provides the backend entities and supporting code for
gnuviechadmin."""

View file

@ -0,0 +1,59 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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 tables import client_table
from gnuviechadmin.exceptions import *
from BackendEntity import *
from BackendEntityHandler import *
class Client(BackendEntity):
"""Entity class for clients."""
_shortkeys = ('clientid', 'firstname', 'lastname', 'email')
def __init__(self, verbose = False, **kwargs):
BackendEntity.__init__(self, verbose)
self.clientid = None
self.country = 'de'
self.title = None
self.address2 = None
self.mobile = None
self.fax = None
for item in kwargs.items():
self.__setattr__(item)
self.validate()
def create_hook(self):
pass
def delete_hook(self):
pass
client_mapper = mapper(Client, client_table)
client_mapper.add_property("sysusers", relation(sysuser.Sysuser))
class ClientHandler(BackendEntityHandler):
"""BackendEntityHandler for Client entities."""
def __init__(self, verbose = False):
BackendEntityHandler.__init__(self, Client, verbose)

View file

@ -0,0 +1,50 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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: client.py 1101 2007-02-28 21:15:20Z jan $
from sqlalchemy import *
from tables import domain_table
from gnuviechadmin.exceptions import *
import record
from BackendEntity import *
from BackendEntityHandler import *
class Domain(BackendEntity):
"""Entity class for DNS domains."""
_shortkeys = ("domainid", "sysuserid", "name", "type")
def __init__(self, verbose = False, **kwargs):
BackendEntity.__init__(self, verbose)
self.domainid = None
self.sysuserid = None
self.name = None
self.type = None
self.validate()
domain_mapper = mapper(Domain, domain_table)
domain_mapper.add_property("records", relation(record.Record))
class DomainHandler(BackendEntityHandler):
"""BackendEntityHandler for Domain entities."""
def __init__(self, verbose = False):
BackendEntityHandler.__init__(self, Domain, verbose)

View file

@ -0,0 +1,52 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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 tables import record_table
from gnuviechadmin.exceptions import *
from BackendEntity import *
from BackendEntityHandler import *
class Record(BackendEntity):
"""Entity class for DNS domain records."""
_shortkeys = ("recordid", "domainid", "name", "type", "content")
def __init__(self, verbose = False, **kwargs):
BackendEntity.__init__(self, verbose)
self.recordid = None
self.domainid = None
self.name = None
self.type = None
self.content = None
self.ttl = None
self.prio = None
self.change_date = None
self.validate()
record_mapper = mapper(Record, record_table)
class RecordHandler(BackendEntityHandler):
"""BackendEntityHandler for Record entities."""
def __init__(self, verbose = False):
BackendEntityHandler.__init__(self, Record, verbose)

View file

@ -0,0 +1,153 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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 tables import sysuser_table
from gnuviechadmin.exceptions import *
from gnuviechadmin.util import passwordutils, getenttools
from BackendEntity import *
from BackendEntityHandler import *
class Sysuser(BackendEntity):
"""Entity class for system users."""
_shortkeys = ("sysuserid", "clientid", "username", "home", "shell")
def __init__(self, verbose = False, **kwargs):
BackendEntity.__init__(self, verbose)
self.sysuserid = None
self.username = None
self.usertype = None
self.home = None
self.shell = None
self.clearpass = None
self.md5pass = None
self.clientid = None
self.sysuid = None
for key in kwargs.keys():
self.__setattr__(key, kwargs[key])
if not self.username:
self.username = self.getnextsysusername()
if not self.usertype:
self.usertype = self.getdefaultsysusertype()
if not self.home:
self.home = self.gethome(self.username)
if not self.shell:
self.shell = self.getdefaultshell()
(self.clearpass, self.md5pass) = \
passwordutils.get_pw_tuple(self.clearpass)
if not self.sysuid:
self.sysuid = self.getnextsysuid()
self.validate()
def getnextsysusername(self):
prefix = self.config.get('sysuser', 'nameprefix')
usernames = [user.username for user in \
getenttools.finduserbyprefix(prefix)]
maxid = max([int(username[len(prefix):]) for username in usernames])
for num in range(1, maxid + 1):
username = "%s%02d" % (prefix, num)
if not username in usernames:
return username
def getdefaultsysusertype(self):
return 1
def gethome(self, sysusername):
"""Gets a valid home directory for the given user name."""
return os.path.join(self.config.get('sysuser', 'homedirbase'),
sysusername)
def getdefaultshell(self):
return False
def getshellbinary(self):
if self.shell:
return self.config.get('sysuser', 'shellyes')
return self.config.get('sysuser', 'shellno')
def getnextsysuid(self):
uid = int(self.config.get('sysuser', 'minuid'))
muid = getenttools.getmaxuid(int(self.config.get('sysuser',
'maxuid')))
if muid >= uid:
uid = muid + 1
return uid
def populate_home(self):
templatedir = self.config.get('sysuser', 'hometemplate')
cmdline = 'install -d --owner="%(username)s" --group="%(group)s" "%(home)s"' % {
'username' : self.username,
'group' : self.config.get('sysuser', 'defaultgroup'),
'home' : self.home }
self.sucommand(cmdline)
cmdline = 'cp -R "%(template)s" "%(home)s"' % {
'template' : templatedir,
'home' : self.home }
self.sucommand(cmdline)
cmdline = 'chown -R "%(username)s":"%(group)s" %(home)s' % {
'username' : self.username,
'group' : self.config.get('sysuser', 'defaultgroup'),
'home' : self.home }
self.sucommand(cmdline)
def create_hook(self):
gecos = self.config.get('sysuser', 'gecos')
gecos = gecos % (self.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.home,
'shell' : self.getshellbinary(),
'sysuid' : self.sysuid,
'group' : self.config.get('sysuser', 'defaultgroup'),
'gecos' : gecos,
'username' : self.username}
self.sucommand(cmdline)
cmdline = 'chpasswd --encrypted'
inline = '%(username)s:%(md5pass)s' % {
'username' : self.username,
'md5pass' : self.md5pass}
self.sucommand(cmdline, inline)
self.populate_home()
def delete_hook(self):
backupdir = os.path.join(self.config.get('common',
'backupdir'),
self.config.get('sysuser',
'homebackupdir'))
if not os.path.isdir(backupdir):
cmdline = 'mkdir -p "%(backupdir)s"' % {
'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.username}
self.sucommand(cmdline)
sysusermapper = mapper(Sysuser, sysuser_table)
class SysuserHandler(BackendEntityHandler):
"""BackendEntityHandler for Sysuser entities."""
def __init__(self, verbose = False):
BackendEntityHandler.__init__(self, Sysuser, verbose)

View file

@ -0,0 +1,93 @@
# -*- coding: UTF-8 -*-
#
# Copyright (C) 2007 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 *
import ConfigParser, os
config = ConfigParser.ConfigParser()
config.readfp(open('gnuviechadmin/defaults.cfg'))
config.read(['gnuviechadmin/gva.cfg', os.path.expanduser('~/.gva.cfg')])
meta = BoundMetaData(config.get('database', 'uri'))
client_table = Table(
'client', meta,
Column('clientid', Integer, primary_key=True),
Column('title', String(10)),
Column('firstname', String(64), nullable=False),
Column('lastname', String(64), nullable=False),
Column('address1', String(64), nullable=False),
Column('address2', String(64)),
Column('zip', String(7), nullable=False),
Column('city', String(64), nullable=False),
Column('country', String(5), nullable=False),
Column('phone', String(32), nullable=False),
Column('mobile', String(32)),
Column('fax', String(32)),
Column('email', String(64), unique=True, nullable=False))
client_table.create(checkfirst=True)
sysuser_table = Table(
'sysuser', meta,
Column('sysuserid', Integer, primary_key=True),
Column('username', String(12), nullable=False, unique=True),
Column('usertype', Integer, nullable=False, default=0, index=True),
Column('home', String(128)),
Column('shell', Boolean, nullable=False, default=False),
Column('clearpass', String(64)),
Column('md5pass', String(34)),
Column('clientid', Integer, ForeignKey("client.clientid"), nullable=False),
Column('sysuid', Integer, nullable=False, unique=True),
Column('lastchange', DateTime, default=func.now())
)
sysuser_table.create(checkfirst=True)
domain_table = Table(
'domain', meta,
Column('domainid', Integer, primary_key=True),
Column('name', String(255), nullable=False, unique=True),
Column('master', String(20)),
Column('last_check', Integer),
Column('type', String(6), nullable=False),
Column('notified_serial', Integer),
Column('sysuserid', Integer, ForeignKey("sysuser.sysuserid"),
nullable=False))
domain_table.create(checkfirst=True)
record_table = Table(
'record', meta,
Column('recordid', Integer, primary_key=True),
Column('domainid', Integer, ForeignKey("domain.domainid"),
nullable=False),
Column('name', String(255)),
Column('type', String(6)),
Column('content', String(255)),
Column('ttl', Integer),
Column('prio', Integer),
Column('change_date', Integer))
record_table.create(checkfirst=True)
supermaster_table = Table(
'supermaster', meta,
Column('ip', String(25), nullable=False),
Column('nameserver', String(255), nullable=False),
Column('account', Integer, ForeignKey("sysuser.sysuserid"),
nullable=False))
supermaster_table.create(checkfirst=True)