- 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:
parent
ee36146629
commit
926acaddfa
19 changed files with 1010 additions and 345 deletions
115
bin/createclient
115
bin/createclient
|
@ -1,115 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- 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 getopt, sys
|
||||
from gnuviechadmin import client, exceptions
|
||||
|
||||
def usage():
|
||||
print """Usage: %s [-h|--help] [-v|--verbose]
|
||||
[-t <title>|--title=<title>]
|
||||
-f <firstname>|--firstname=<firstname> -l <lastname>|--lastname=<lastname>
|
||||
-a <address1>|--address=<address1> [--address2=<address2>]
|
||||
-z <zip>|--zip=<zip> -c <city>|--city=<city> [--country=<isocode>]
|
||||
[-o <organisation>|--organisation=<organisation>]
|
||||
-e <email>|--email=<email> -p <phone>|--phone=<phone>
|
||||
[-m <mobile>|--mobile=<mobile>] [-x <fax>|--fax=<fax>]
|
||||
|
||||
General options:
|
||||
-h, --help show this usage message and exit
|
||||
-v, --verbose verbose operation
|
||||
|
||||
Mandatory client data options:
|
||||
-f, --firstname firstname
|
||||
-l, --lastname lastname
|
||||
-a, --address street address
|
||||
-z, --zip zip or postal code
|
||||
-c, --city city or location
|
||||
-e, --email contact email address
|
||||
-p, --phone telephone number
|
||||
|
||||
Optional client data options:
|
||||
--address2 optional second line of the street address
|
||||
-o, --organisation option organisation
|
||||
--country country (defaults to de)
|
||||
-t, --title optional title
|
||||
-m, --mobile optional mobile number
|
||||
-x, --fax optional fax number
|
||||
""" % (sys.argv[0])
|
||||
|
||||
def main():
|
||||
try:
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:],
|
||||
"hvf:l:a:z:c:e:p:o:t:m:x:",
|
||||
["help", "verbose", "firstname=",
|
||||
"lastname=", "address=", "zip=",
|
||||
"city=", "email=", "phone=",
|
||||
"address2=", "organisation=",
|
||||
"country=", "title=", "mobile=",
|
||||
"fax="])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
clientdata = {}
|
||||
verbose = False
|
||||
for o, a in opts:
|
||||
if o in ("-v", "--verbose"):
|
||||
verbose = True
|
||||
if o in ("-h", "--help"):
|
||||
usage()
|
||||
sys.exit()
|
||||
if o in ("-f", "--firstname"):
|
||||
clientdata["firstname"] = a
|
||||
if o in ("-l", "--lastname"):
|
||||
clientdata["lastname"] = a
|
||||
if o in ("-a", "--address"):
|
||||
clientdata["address1"] = a
|
||||
if o in ("-z", "--zip"):
|
||||
clientdata["zip"] = a
|
||||
if o in ("-c", "--city"):
|
||||
clientdata["city"] = a
|
||||
if o == "--country":
|
||||
clientdata["country"] = a
|
||||
if o in ("-t", "--title"):
|
||||
clientdata["title"] = a
|
||||
if o in ("-m", "--mobile"):
|
||||
clientdata["mobile"] = a
|
||||
if o in ("-e", "--email"):
|
||||
clientdata["email"] = a
|
||||
if o in ("-o", "--organisation"):
|
||||
clientdata["organisation"] = a
|
||||
if o in ("-x", "--fax"):
|
||||
clientdata["fax"] = a
|
||||
if o in ("-p", "--phone"):
|
||||
clientdata["phone"] = a
|
||||
if verbose:
|
||||
print "parsed client data is ", clientdata
|
||||
try:
|
||||
myclient = client.create(**clientdata)
|
||||
except exceptions.CreationFailedError, cfe:
|
||||
usage()
|
||||
print cfe
|
||||
sys.exit(2)
|
||||
if verbose:
|
||||
print myclient
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
16
bin/gva
16
bin/gva
|
@ -24,14 +24,16 @@ import gnuviechadmin.cli.client
|
|||
import gnuviechadmin.cli.sysuser
|
||||
import sys
|
||||
|
||||
commands = [gnuviechadmin.cli.client.ClientCli,
|
||||
gnuviechadmin.cli.sysuser.SysuserCli]
|
||||
|
||||
def usage():
|
||||
print """%s <command> [commandargs]
|
||||
|
||||
where command is one of
|
||||
|
||||
client - for creating clients
|
||||
sysuser - for creating system users
|
||||
""" % sys.argv[0]
|
||||
for command in commands:
|
||||
print "%10s - %s" % (command.name, command.description)
|
||||
|
||||
def main():
|
||||
if (sys.argv.__len__() < 2):
|
||||
|
@ -39,10 +41,10 @@ def main():
|
|||
sys.exit()
|
||||
command = sys.argv[1]
|
||||
commargs = sys.argv[2:]
|
||||
if command == "client":
|
||||
gnuviechadmin.cli.client.ClientCli(commargs)
|
||||
elif command == "sysuser":
|
||||
gnuviechadmin.cli.sysuser.SysuserCli(commargs)
|
||||
if command in [cmd.name for cmd in commands]:
|
||||
for cmd in commands:
|
||||
if cmd.name == command:
|
||||
cmd(commargs)
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
|
83
gnuviechadmin/backend/BackendEntity.py
Normal file
83
gnuviechadmin/backend/BackendEntity.py
Normal 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)
|
69
gnuviechadmin/backend/BackendEntityHandler.py
Normal file
69
gnuviechadmin/backend/BackendEntityHandler.py
Normal 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)
|
13
bin/listclients → gnuviechadmin/backend/__init__.py
Executable file → Normal file
13
bin/listclients → gnuviechadmin/backend/__init__.py
Executable file → Normal file
|
@ -1,4 +1,3 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright (C) 2007 by Jan Dittberner.
|
||||
|
@ -17,12 +16,10 @@
|
|||
# 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 gnuviechadmin import client
|
||||
"""This is the gnuviechadmin.backend package.
|
||||
|
||||
def main():
|
||||
for row in client.fetchall():
|
||||
print row
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
The package provides the backend entities and supporting code for
|
||||
gnuviechadmin."""
|
59
gnuviechadmin/backend/client.py
Normal file
59
gnuviechadmin/backend/client.py
Normal 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)
|
50
gnuviechadmin/backend/domain.py
Normal file
50
gnuviechadmin/backend/domain.py
Normal 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)
|
52
gnuviechadmin/backend/record.py
Normal file
52
gnuviechadmin/backend/record.py
Normal 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)
|
153
gnuviechadmin/backend/sysuser.py
Normal file
153
gnuviechadmin/backend/sysuser.py
Normal 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)
|
|
@ -52,9 +52,42 @@ sysuser_table = Table(
|
|||
Column('home', String(128)),
|
||||
Column('shell', Boolean, nullable=False, default=False),
|
||||
Column('clearpass', String(64)),
|
||||
Column('md5pass', String(32)),
|
||||
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)
|
|
@ -20,62 +20,202 @@
|
|||
# Version: $Id$
|
||||
|
||||
import getopt, sys
|
||||
from gnuviechadmin.exceptions import GnuviechadminError
|
||||
|
||||
class CliCommand:
|
||||
"""Base class for command line interface."""
|
||||
def usage(self):
|
||||
"""This method should print usage information for the command."""
|
||||
"""Base class for command line interface. A specific
|
||||
implementation class must define the fields name, description and
|
||||
_optionmap.
|
||||
|
||||
|
||||
The field name is the name of the subcommand.
|
||||
|
||||
The field description is a short, one line description of the
|
||||
command.
|
||||
|
||||
The field _optionmap is a map which maps the subcommand names to
|
||||
lists of tuples. Each tuple consists of four elements. The first
|
||||
element is a list of command line arguments, short arguments start
|
||||
with dash, long arguments with a double dash. The second element
|
||||
is the name of the field in the data map of the command, it will
|
||||
directly be sent to the underlying entity. The third field is a
|
||||
description for the group of command line options in field
|
||||
one. The fourth field is True for mandatory fields and False
|
||||
otherwise.
|
||||
"""
|
||||
|
||||
def _usage(self):
|
||||
"""This method shows usage information. The implementation
|
||||
relies on the information in the fields name, description and
|
||||
_optionmap in the implementation classes."""
|
||||
print """GNUViechAdmin command line interface
|
||||
|
||||
Subcommand: %(command)s
|
||||
|
||||
%(description)s
|
||||
|
||||
Usage:
|
||||
|
||||
%(called)s %(command)s -h|--help
|
||||
|
||||
gives this usage information.
|
||||
|
||||
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' : " "}
|
||||
for commandname in self._optionmap.keys():
|
||||
cmdl = "%(called)s %(command)s %(subcommand)s [-v|--verbose]" % {
|
||||
'called' : sys.argv[0],
|
||||
'command' : self.name,
|
||||
'subcommand' : commandname}
|
||||
desc = """
|
||||
%s
|
||||
""" % (self._optionmap[commandname][0])
|
||||
for (options, field, optiondesc, mandatory) in \
|
||||
self._optionmap[commandname][1]:
|
||||
cmd = " "
|
||||
pairs = []
|
||||
for option in options:
|
||||
if field:
|
||||
if option.startswith("--"):
|
||||
pairs.append("%s=<%s>" % (option, field))
|
||||
else:
|
||||
pairs.append("%s <%s>" % (option, field))
|
||||
else:
|
||||
pairs.append(option)
|
||||
if not mandatory:
|
||||
cmd = cmd + "["
|
||||
cmd = cmd + "|".join(pairs)
|
||||
if not mandatory:
|
||||
cmd = cmd + "]"
|
||||
descmap = {
|
||||
'option' : ", ".join(pairs),
|
||||
'optiondesc' : optiondesc,
|
||||
'mandatory' : ' '}
|
||||
if mandatory:
|
||||
descmap['mandatory'] = '*'
|
||||
desc = desc + """ %(option)s
|
||||
%(mandatory)s %(optiondesc)s
|
||||
""" % descmap
|
||||
if (len(cmdl) + len(cmd)) > 79:
|
||||
print cmdl
|
||||
cmdl = cmd
|
||||
else:
|
||||
cmdl = cmdl + cmd
|
||||
print cmdl
|
||||
print desc
|
||||
print "Mandatory options are marked with *"
|
||||
|
||||
def _subcommands(self):
|
||||
"""Convenience method for retrieving the subcommand names from
|
||||
the _optionmap field."""
|
||||
return self._optionmap.keys()
|
||||
|
||||
def _longopts(self, subcommand):
|
||||
"""This method retrieves available long options in a format
|
||||
valid for getopt.gnu_getopt(...) from the _optionmap field."""
|
||||
longopts = []
|
||||
for cur in [(option[0], option[1]) for option in \
|
||||
self._optionmap[subcommand][1]]:
|
||||
for command in cur[0]:
|
||||
if command.startswith("--"):
|
||||
if cur[1]:
|
||||
longopts.append(command[2:] + "=")
|
||||
else:
|
||||
longopts.append(command[2:])
|
||||
return longopts
|
||||
|
||||
def _shortopts(self, subcommand):
|
||||
"""This method retrieves available short options in a format
|
||||
valid for getopt.gnu_getopt(...) from the _optionmap field."""
|
||||
shortopts = ""
|
||||
for cur in [(option[0], option[1]) for option in \
|
||||
self._optionmap[subcommand][1]]:
|
||||
for command in cur[0]:
|
||||
if not command.startswith("--"):
|
||||
if cur[1]:
|
||||
shortopts = shortopts + command[1:] + ":"
|
||||
else:
|
||||
shortopts = shortopts + command[1:]
|
||||
return shortopts
|
||||
|
||||
def _checkrequired(self, subcommand):
|
||||
"""Checks whether the required fields of the given subcommand
|
||||
are set."""
|
||||
reqcheck = [True, []]
|
||||
for req in [option for option in \
|
||||
self._optionmap[subcommand][1] if option[3]]:
|
||||
if not req[1] in self._data:
|
||||
reqcheck[0] = False
|
||||
reqcheck[1].append(""" %s
|
||||
* %s""" % (", ".join(req[0]), req[2]))
|
||||
return reqcheck
|
||||
|
||||
def _handleoption(self, subcommand, o, a):
|
||||
"""Handles a command line option by assigning it to the
|
||||
matching key as defined in the _optionmap property of the
|
||||
implementation class."""
|
||||
optionmap = [(option[0], option[1]) for option in \
|
||||
self._optionmap[subcommand][1]]
|
||||
if optionmap:
|
||||
for (options, datakey) in optionmap:
|
||||
if o in options:
|
||||
self._data[datakey] = a
|
||||
|
||||
def _execute(self, subcommand):
|
||||
"""This method is called when the subcommand of the command is
|
||||
executed."""
|
||||
raise NotImplementedError
|
||||
|
||||
def shortopts(self):
|
||||
"""This method should return an option string for the short
|
||||
options for getopt.gnu_getopt(...)."""
|
||||
raise NotImplementedError
|
||||
|
||||
def longopts(self):
|
||||
"""This method should return a list of long options for
|
||||
getopt.gnu_getopt(...)."""
|
||||
raise NotImplementedError
|
||||
|
||||
def handleoption(self, option, argument):
|
||||
"""This method should handle each option known to the command."""
|
||||
raise NotImplementedError
|
||||
|
||||
def execute(self):
|
||||
"""This method is called when the command is executed."""
|
||||
raise NotImplementedError
|
||||
|
||||
def checkrequired(self):
|
||||
"""This methode is called after handling command line options
|
||||
and should check whether all required values were set."""
|
||||
raise NotImplementedError
|
||||
|
||||
def __parseopts(self, args):
|
||||
def _parseopts(self, subcommand, args):
|
||||
"""This method parses the options given on the command line."""
|
||||
longopts = ["help", "verbose"]
|
||||
longopts.extend(self.longopts())
|
||||
longopts.extend(self._longopts(subcommand))
|
||||
try:
|
||||
opts, args = getopt.gnu_getopt(
|
||||
args,
|
||||
"hv" + self.shortopts(),
|
||||
"hv" + self._shortopts(subcommand),
|
||||
longopts)
|
||||
except getopt.GetoptError:
|
||||
self.usage()
|
||||
self._usage()
|
||||
sys.exit(2)
|
||||
self.verbose = False
|
||||
self._verbose = False
|
||||
for o, a in opts:
|
||||
if o in ("-v", "--verbose"):
|
||||
self.verbose = True
|
||||
self._verbose = True
|
||||
if o in ("-h", "--help"):
|
||||
self.usage()
|
||||
self._usage()
|
||||
sys.exit()
|
||||
self.handleoption(o, a)
|
||||
self._handleoption(subcommand, o, a)
|
||||
|
||||
def __init__(self, args):
|
||||
"""This initializes the command with the given command line
|
||||
arguments and executes it."""
|
||||
self.__parseopts(args)
|
||||
if (self.checkrequired()):
|
||||
self.execute()
|
||||
self._data = {}
|
||||
if len(args) > 0:
|
||||
if args[0] in self._subcommands():
|
||||
self._parseopts(args[0], args[1:])
|
||||
reqcheck = self._checkrequired(args[0])
|
||||
if reqcheck[0]:
|
||||
try:
|
||||
self._execute(args[0])
|
||||
except GnuviechadminError, e:
|
||||
print e
|
||||
else:
|
||||
self.usage()
|
||||
self._usage()
|
||||
print """
|
||||
the following required arguments are missing:
|
||||
"""
|
||||
print "\n".join(reqcheck[1])
|
||||
else:
|
||||
self._usage()
|
||||
print "invalid sub command"
|
||||
else:
|
||||
self._usage()
|
||||
|
|
|
@ -20,91 +20,63 @@
|
|||
# Version: $Id$
|
||||
|
||||
import CliCommand, sys
|
||||
from gnuviechadmin import client
|
||||
|
||||
class ClientCli(CliCommand.CliCommand):
|
||||
"""Command line interface command for client creation."""
|
||||
def shortopts(self):
|
||||
return "f:l:a:z:c:e:p:o:t:m:x:"
|
||||
"""Command line interface command for client managament."""
|
||||
|
||||
def longopts(self):
|
||||
return ["firstname=", "lastname=", "address=", "zip=",
|
||||
"city=", "email=", "phone=", "address2=", "organisation=",
|
||||
"country=", "title=", "mobile=", "fax="]
|
||||
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)])}
|
||||
|
||||
def usage(self):
|
||||
print """Usage: %s client [-h|--help] [-v|--verbose]
|
||||
[-t <title>|--title=<title>]
|
||||
-f <firstname>|--firstname=<firstname> -l <lastname>|--lastname=<lastname>
|
||||
-a <address1>|--address=<address1> [--address2=<address2>]
|
||||
-z <zip>|--zip=<zip> -c <city>|--city=<city> [--country=<isocode>]
|
||||
[-o <organisation>|--organisation=<organisation>]
|
||||
-e <email>|--email=<email> -p <phone>|--phone=<phone>
|
||||
[-m <mobile>|--mobile=<mobile>] [-x <fax>|--fax=<fax>]
|
||||
|
||||
General options:
|
||||
-h, --help show this usage message and exit
|
||||
-v, --verbose verbose operation
|
||||
|
||||
Mandatory client data options:
|
||||
-f, --firstname firstname
|
||||
-l, --lastname lastname
|
||||
-a, --address street address
|
||||
-z, --zip zip or postal code
|
||||
-c, --city city or location
|
||||
-e, --email contact email address
|
||||
-p, --phone telephone number
|
||||
|
||||
Optional client data options:
|
||||
--address2 optional second line of the street address
|
||||
-o, --organisation option organisation
|
||||
--country country (defaults to de)
|
||||
-t, --title optional title
|
||||
-m, --mobile optional mobile number
|
||||
-x, --fax optional fax number
|
||||
""" % sys.argv[0]
|
||||
|
||||
def handleoption(self, o, a):
|
||||
if o in ("-f", "--firstname"):
|
||||
self.data["firstname"] = a
|
||||
elif o in ("-l", "--lastname"):
|
||||
self.data["lastname"] = a
|
||||
elif o in ("-a", "--address"):
|
||||
self.data["address1"] = a
|
||||
elif o in ("-z", "--zip"):
|
||||
self.data["zip"] = a
|
||||
elif o in ("-c", "--city"):
|
||||
self.data["city"] = a
|
||||
elif o == "--country":
|
||||
self.data["country"] = a
|
||||
elif o in ("-t", "--title"):
|
||||
self.data["title"] = a
|
||||
elif o in ("-m", "--mobile"):
|
||||
self.data["mobile"] = a
|
||||
elif o in ("-e", "--email"):
|
||||
self.data["email"] = a
|
||||
elif o in ("-o", "--organisation"):
|
||||
self.data["organisation"] = a
|
||||
elif o in ("-x", "--fax"):
|
||||
self.data["fax"] = a
|
||||
elif o in ("-p", "--phone"):
|
||||
self.data["phone"] = a
|
||||
|
||||
def checkrequired(self):
|
||||
required = ['firstname', 'lastname', 'address1', 'zip', 'city',
|
||||
'phone', 'email']
|
||||
if self.verbose:
|
||||
print self.data
|
||||
for req in required:
|
||||
if not req in self.data:
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self):
|
||||
myclient = client.create(**self.data)
|
||||
if self.verbose:
|
||||
def _execute(self, subcommand):
|
||||
from gnuviechadmin.backend import client
|
||||
from gnuviechadmin import exceptions
|
||||
if subcommand == "create":
|
||||
try:
|
||||
myclient = client.ClientHandler(self._verbose).create(
|
||||
**self._data)
|
||||
if self._verbose:
|
||||
print myclient
|
||||
except exceptions.CreationFailedError, cfe:
|
||||
self._usage()
|
||||
print cfe
|
||||
sys.exit(2)
|
||||
elif subcommand == "list":
|
||||
clients = client.ClientHandler(self._verbose).fetchall()
|
||||
for client in clients:
|
||||
print client
|
||||
elif subcommand == "delete":
|
||||
client.ClientHandler(self._verbose).delete(self._data["clientid"])
|
||||
|
||||
def __init__(self, argv):
|
||||
self.data = {}
|
||||
CliCommand.CliCommand.__init__(self, argv)
|
||||
|
|
|
@ -1 +1,71 @@
|
|||
pass
|
||||
# -*- 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 CliCommand, sys
|
||||
|
||||
class SysuserCli(CliCommand.CliCommand):
|
||||
"""Command line interface command for system user managament."""
|
||||
|
||||
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)])}
|
||||
|
||||
def _execute(self, subcommand):
|
||||
from gnuviechadmin.backend import sysuser
|
||||
from gnuviechadmin import exceptions
|
||||
if subcommand == "create":
|
||||
try:
|
||||
mysysuser = sysuser.SysuserHandler(self._verbose).create(
|
||||
**self._data)
|
||||
if self._verbose:
|
||||
print mysysuser
|
||||
except exceptions.CreationFailedError, cfe:
|
||||
self._usage()
|
||||
print cfe
|
||||
sys.exit(2)
|
||||
elif subcommand == "list":
|
||||
sysusers = sysuser.SysuserHandler(self._verbose).fetchall()
|
||||
for su in sysusers:
|
||||
print su
|
||||
elif subcommand == "delete":
|
||||
sysuser.SysuserHandler(self._verbose).delete(
|
||||
self._data["sysuserid"])
|
||||
|
||||
def __init__(self, argv):
|
||||
CliCommand.CliCommand.__init__(self, argv)
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
# -*- 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.tables import *
|
||||
from gnuviechadmin import sysuser
|
||||
from gnuviechadmin.exceptions import *
|
||||
|
||||
class Client(object):
|
||||
mandatory = ('firstname', 'lastname', 'address1', 'zip', 'city',
|
||||
'country', 'phone', 'email')
|
||||
|
||||
"""This class provides a client representation"""
|
||||
def __init__(self, **kwargs):
|
||||
self.clientid = None
|
||||
self.country = 'de'
|
||||
self.title = None
|
||||
self.address2 = None
|
||||
self.mobile = None
|
||||
self.fax = None
|
||||
self.organisation = None
|
||||
for key in kwargs.keys():
|
||||
self.__setattr__(key, kwargs[key])
|
||||
self.validate()
|
||||
|
||||
def validate(self):
|
||||
missingfields = []
|
||||
for key in self.mandatory:
|
||||
if self.__getattribute__(key) is None:
|
||||
missingfields.append(key)
|
||||
if missingfields:
|
||||
raise MissingFieldsError(missingfields)
|
||||
|
||||
def __repr__(self):
|
||||
return "%(clientid)d,%(firstname)s,%(lastname)s,%(email)s" % (
|
||||
{'clientid' : self.clientid, 'firstname' : self.firstname,
|
||||
'lastname' : self.lastname, 'email' : self.email})
|
||||
|
||||
clientmapper = mapper(
|
||||
Client, client_table,
|
||||
properties = {'sysusers': relation(sysuser.Sysuser)})
|
||||
|
||||
def create(**kwargs):
|
||||
try:
|
||||
myclient = Client(**kwargs)
|
||||
sess = create_session()
|
||||
sess.save(myclient)
|
||||
sess.flush()
|
||||
except MissingFieldsError, mfe:
|
||||
raise CreationFailedError(Client.__name__, mfe)
|
||||
except exceptions.SQLError, sqle:
|
||||
raise CreationFailedError(Client.__name__, sqle)
|
||||
return myclient
|
||||
|
||||
def fetchall():
|
||||
session = create_session()
|
||||
query = session.query(Client)
|
||||
return query.select()
|
|
@ -32,3 +32,19 @@
|
|||
# very usable for a real installation.
|
||||
#
|
||||
uri = sqlite:///:memory:
|
||||
|
||||
[common]
|
||||
suwrapper = sudo
|
||||
backupdir = /var/backups/gnuviechadmin
|
||||
|
||||
[sysuser]
|
||||
nameprefix = usr
|
||||
homedirbase = /home/www
|
||||
minuid = 10000
|
||||
maxuid = 39999
|
||||
shellyes = /bin/bash
|
||||
shellno = /usr/bin/scponly
|
||||
defaultgroup = wwwusers
|
||||
gecos = Webuser %s
|
||||
homebackupdir = homes
|
||||
hometemplate = /etc/gnuviechadmin/templates/home
|
||||
|
|
|
@ -20,18 +20,24 @@
|
|||
# Version: $Id$
|
||||
|
||||
"""This file defines the gnuviechadmin specific exception types."""
|
||||
class MissingFieldsError(Exception):
|
||||
|
||||
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."""
|
||||
class is missing."""
|
||||
def __init__(self, missingfields):
|
||||
self.missing = missingfields
|
||||
|
||||
def __str__(self):
|
||||
return "the fields %s are missing." % (repr(self.missing))
|
||||
|
||||
class CreationFailedError(Exception):
|
||||
class CreationFailedError(GnuviechadminError):
|
||||
"""This exception should be raised if a business object could not
|
||||
be created."""
|
||||
be created."""
|
||||
def __init__(self, classname, cause = None):
|
||||
self.classname = classname
|
||||
self.cause = cause
|
||||
|
@ -41,3 +47,16 @@ be created."""
|
|||
if self.cause:
|
||||
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
|
||||
|
||||
def __str__(self):
|
||||
msg = "Deleting an instance of class %s failed." % (self.classname)
|
||||
if self.cause:
|
||||
msg += " The reason is %s." % (str(self.cause))
|
||||
return msg
|
||||
|
|
|
@ -19,16 +19,6 @@
|
|||
#
|
||||
# Version: $Id$
|
||||
|
||||
from sqlalchemy import *
|
||||
from gnuviechadmin.tables import *
|
||||
from gnuviechadmin.exceptions import *
|
||||
"""This is the gnuviechadmin.util package.
|
||||
|
||||
class Sysuser(object):
|
||||
def __repr__(self):
|
||||
return "%(sysuserid)d,%(username)s,%(clientid)d,%(sysuid)d" % ({
|
||||
'sysuserid': self.sysuserid,
|
||||
'username': self.username,
|
||||
'clientid': self.clientid,
|
||||
'sysuid': self.sysuid})
|
||||
|
||||
sysusermapper = mapper(Sysuser, sysuser_table)
|
||||
The package provides utility modules for various functions."""
|
94
gnuviechadmin/util/getenttools.py
Normal file
94
gnuviechadmin/util/getenttools.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
# -*- 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 os, popen2
|
||||
|
||||
class PasswdUser(object):
|
||||
"""This class represents users in the user database."""
|
||||
def __init__(self, username, pw, uid, gid, gecos, home, shell):
|
||||
self.username = username
|
||||
self.uid = int(uid)
|
||||
self.gid = int(gid)
|
||||
self.gecos = gecos
|
||||
self.home = home
|
||||
self.shell = shell
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%s:%d:%d:%s:%s:%s)" % (self.__class__.__name__,
|
||||
self.username,
|
||||
self.uid,
|
||||
self.gid,
|
||||
self.gecos,
|
||||
self.home,
|
||||
self.shell)
|
||||
|
||||
class PasswdGroup(object):
|
||||
"""This class represents lines in the groups database."""
|
||||
def __init__(self, groupname, pw, gid, members):
|
||||
self.groupname = groupname
|
||||
self.gid = int(gid)
|
||||
self.members = members.split(",")
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%s:%d:%s)" % (self.__class__.__name__,
|
||||
self.groupname,
|
||||
self.gid,
|
||||
",".join(self.members))
|
||||
|
||||
def parsegroups():
|
||||
(stdout, stdin) = popen2.popen2("getent group")
|
||||
return [PasswdGroup(*arr) for arr in [line.strip().split(":") for line in stdout]]
|
||||
|
||||
def parseusers():
|
||||
(stdout, stdin) = popen2.popen2("getent passwd")
|
||||
return [PasswdUser(*arr) for arr in [line.strip().split(":") for line in stdout]]
|
||||
|
||||
def finduserbyprefix(prefix):
|
||||
"""Finds all user entries with the given prefix."""
|
||||
return [user for user in parseusers() if user.username.startswith(prefix)]
|
||||
|
||||
def getuserbyid(uid):
|
||||
"""Gets the user with the given user id."""
|
||||
users = [user for user in parseusers() if user.uid == uid]
|
||||
if users:
|
||||
return users[0]
|
||||
return None
|
||||
|
||||
def getgroupbyid(gid):
|
||||
"""Gets the group with the given group id."""
|
||||
groups = [group for group in parsegroups() if group.gid == gid]
|
||||
if groups:
|
||||
return groups[0]
|
||||
return None
|
||||
|
||||
def getmaxuid(boundary = 65536):
|
||||
"""Gets the highest uid value."""
|
||||
return max([user.uid for user in parseusers() if user.uid <= boundary])
|
||||
|
||||
def getmaxgid(boundary = 65536):
|
||||
"""Gets the highest gid value."""
|
||||
return max([group.gid for group in parsegroups() if group.gid <= boundary])
|
||||
|
||||
if __name__ == "__main__":
|
||||
print "Max UID is %d" % (getmaxuid(40000))
|
||||
print "Max GID is %d" % (getmaxgid(40000))
|
||||
print "User with max UID is %s" % (getuserbyid(getmaxuid(40000)))
|
||||
print "Group with max GID is %s" % (getgroupbyid(getmaxgid(40000)))
|
57
gnuviechadmin/util/passwordutils.py
Normal file
57
gnuviechadmin/util/passwordutils.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
# -*- 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 crypt, crack, random
|
||||
|
||||
def generatepassword(minlength = 8, maxlength = 12):
|
||||
"""Generates a random password with a length between the given
|
||||
minlength and maxlength values."""
|
||||
pwchars = []
|
||||
for pair in (('0', '9'), ('A', 'Z'), ('a', 'z')):
|
||||
pwchars.extend(range(ord(pair[0]), ord(pair[1])))
|
||||
for char in "-+/*_@":
|
||||
pwchars.append(ord(char))
|
||||
return "".join([chr(letter) for letter in \
|
||||
random.sample(pwchars,
|
||||
random.randint(minlength, maxlength))])
|
||||
|
||||
def checkpassword(password):
|
||||
"""Checks the password with cracklib. The password is returned if
|
||||
it is good enough. Otherwise None is returned."""
|
||||
try:
|
||||
return crack.VeryFascistCheck(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."""
|
||||
salt = "".join([chr(letter) for letter in \
|
||||
random.sample(range(ord('a'), ord('z')), 8)])
|
||||
return crypt.crypt(password, '$1$' + salt)
|
||||
|
||||
def get_pw_tuple(password = None):
|
||||
"""Gets a valid tuple consisting of a password and a md5 hash of the
|
||||
password. If a password is given it is checked and if it is too weak
|
||||
replaced by a generated one."""
|
||||
while password == None or checkpassword(password) == None:
|
||||
password = generatepassword()
|
||||
return (password, md5_crypt_password(password))
|
Loading…
Reference in a new issue