logging cleaned up

unified errorExit function instead of explicite sys.exit calls
add config_file argument to CryptoBoxProps
add getCapacity method to CryptoBoxContainer
removed "classes.txt"
This commit is contained in:
lars 2006-08-24 07:36:47 +00:00
parent bb16749b81
commit 707fb71476
5 changed files with 168 additions and 85 deletions

View file

@ -5,9 +5,6 @@ This is the web interface for a fileserver managing encrypted filesystems.
It was originally written in bash/perl. Now a complete rewrite is in
progress. So things might be confusing here. Hopefully not for long.
:)
TODO: replace all "sys.exit"-calls by a unified handler
'''
# check python version
@ -30,7 +27,6 @@ CONF_LOCATIONS = [
"~/.cryptobox.conf",
"/etc/cryptobox/cryptobox.conf"]
SUDO_WRAPPER = ["sudo", "/home/lars/subversion/cryptobox/branches/pythonrewrite/bin2/CryptoBoxRootActions.py"]
class CryptoBox:
'''this class rules them all!
@ -56,24 +52,22 @@ class CryptoBox:
to the configured destination'''
## basicConfig(...) needs python >= 2.4
try:
logging.basicConfig(
format='%(asctime)s %(module)s %(levelname)s %(message)s',
stream = sys.stderr)
self.log = logging.getLogger("CryptoBox")
self.log.setLevel(logging.INFO)
logging.basicConfig(
format='%(asctime)s %(module)s %(levelname)s %(message)s',
stderr=sys.stderr)
self.log.setLevel(logging.ERROR)
self.log.info("loggingsystem is up'n running")
## from now on everything can be logged via self.log...
except:
sys.stderr.write("Something with the loggingsystem went wrong. I give up.")
sys.exit(1)
sys.errorExit("SystemError","Something with the loggingsystem went wrong. I give up.")
def __initPreferences(self, config_file):
try:
import configobj ## needed for reading and writing of the config file
except:
self.log.error("Could't import 'configobj'! Try 'apt-get install python-configobj'.")
sys.exit(1)
self.errorExit("SystemError", "Could't import 'configobj'! Try 'apt-get install python-configobj'.")
# search for the configuration file
if config_file is None:
# no config file was specified - we will look for it in the ususal locations
@ -82,57 +76,56 @@ class CryptoBox:
if os.path.exists(os.path.expanduser(f))]
if not conf_file_list:
# no possible config file found in the usual locations
self.log.error("No configuration file found - sorry!")
sys.exit(1)
self.errorExit("ConfigError", "No configuration file found - sorry!")
config_file = conf_file_list[0]
else:
# a config file was specified (e.g. via command line)
if type(config_file) != types.StringType:
self.errorExit("ConfigError","Invalid config file specified: %s" % config_file)
if not os.path.exists(config_file):
self.log.error("Could not find the specified configuration file (%s)" % config_file)
sys.exit(1)
self.errorExit("ConfigError","Could not find the specified configuration file (%s)" % config_file)
try:
self.cbxPrefs = configobj.ConfigObj(config_file)
if self.cbxPrefs:
self.log.info("found config: %s" % self.cbxPrefs.items())
else:
FileNotFound = "could not find %s" % config_file
raise FileNotFound
except FileNotFound:
self.log.error(FileNotFound)
sys.exit(1)
self.errorExit("ConfigError","failed to load the config file: %s" % config_file)
except IOError:
self.errorExit("ConfigError","unable to open the config file: %s" % config_file)
try:
nameDB_file = os.path.join(
self.cbxPrefs["Main"]["DataDir"],
self.cbxPrefs["Main"]["NameDatabase"])
try:
nameDB_file = os.path.join(
self.cbxPrefs["Main"]["DataDir"],
self.cbxPrefs["Main"]["NameDatabase"])
except KeyError:
self.errorExit("ConfigError","could not find one of these configuration settings: [Main]->DataDir and [Main]->NameDatabase - please check your config file(%s)" % config_file)
if os.path.exists(nameDB_file):
self.nameDB = configobj.ConfigObj(nameDB_file)
else:
self.nameDB = configobj.ConfigObj(nameDB_file, create_empty=True)
except SyntaxError:
self.log.error("Error during parsing of name database file (%s).\n" % (nameDB_file, ))
sys.exit(1)
self.errorExit("ConfigError","Error during parsing of name database file (%s).\n" % (nameDB_file, ))
# TODO: check if nameDB file was created successfully?
# get the loglevel
try:
log_level = self.cbxPrefs["Log"]["Level"].upper()
log_level_avail = ["DEBUG", "INFO", "WARN", "ERROR"]
#if not log_level in ["DEBUG", "INFO", "WARN", "ERROR"]:
if not log_level in log_level_avail:
self.log.error("invalid log level: %s is not in %s" % (self.cbxPrefs["Log"]["Level"], log_level_avail))
sys.exit(1)
self.errorExit("ConfigError","invalid log level: %s is not in %s" % (self.cbxPrefs["Log"]["Level"], log_level_avail))
except TypeError:
self.log.error("invalid log level: %s" % self.cbxPrefs["Log"]["Level"])
sys.exit(1)
self.errorExit("ConfigError","invalid log level: %s" % self.cbxPrefs["Log"]["Level"])
try:
new_handler = logging.FileHandler(self.cbxPrefs["Log"]["Details"])
# TODO: loglevel doesn't change after first initialisation
new_handler.setLevel(getattr(logging, log_level))
# TODO: this formatter does not work for now
new_handler.setFormatter = '%(asctime)s %(module)s %(levelname)s %(message)s'
try:
new_handler = logging.FileHandler(self.cbxPrefs["Log"]["Details"])
except KeyError:
self.errorExit("ConfigError","could not find a configuration setting: [Log]->Details - please check your config file(%s)" % config_file)
new_handler.setFormatter(logging.Formatter('%(asctime)s %(module)s %(levelname)s: %(message)s'))
self.log.addHandler(new_handler)
# do not call parent's handlers
self.log.propagate = False
self.log.setLevel(getattr(logging,log_level))
except IOError:
self.log.error("could not open logfile: %s" % self.cbxPrefs["Log"]["Details"])
sys.exit(1)
self.errorExit("ConfigError","could not open logfile: %s" % self.cbxPrefs["Log"]["Details"])
# do some initial checks
@ -140,8 +133,7 @@ class CryptoBox:
try:
devnull = open(os.devnull, "w")
except IOError:
self.log.error("Could not open %s for writing!" % os.devnull)
sys.exit(1)
self.errorExit("SystemError","Could not open %s for writing!" % os.devnull)
try:
proc = subprocess.Popen(
shell = False,
@ -151,17 +143,37 @@ class CryptoBox:
self.cbxPrefs["Programs"]["CryptoBoxRootActions"],
"check"])
except OSError:
self.log.error("could not find: %s" % self.cbxPrefs["Programs"]["super"])
sys.exit(1)
self.errorExit("ConfigError","could not find: %s" % self.cbxPrefs["Programs"]["super"])
proc.wait()
if proc.returncode != 0:
self.log.error("Could not call CryptoBoxRootActions by 'super' - maybe you did not add the appropriate line to /etc/super.tab?")
sys.exit(1)
self.errorExit("ConfigError","Could not call CryptoBoxRootActions by 'super' - maybe you did not add the appropriate line to /etc/super.tab?")
# this method just demonstrates inheritance effects - may be removed
def cbx_inheritance_test(self, string="you lucky widow"):
self.log.info(string)
def errorExitMod(self, title, msg, code=1):
"""output an error message and quit by raising an exception
this function should be used if this class was used as a module instead
of as a standalone program
"""
self.log.error(msg)
raise title, msg
def errorExitProg(self, title, msg, code=1):
"""output an error message and quit by calling sys.exit
this function should be used if this class was used as a standalone
program
"""
self.log.error(msg)
sys.exit(code)
# RFC: why should CryptoBoxProps inherit CryptoBox? [l]
@ -173,9 +185,9 @@ class CryptoBoxProps(CryptoBox):
All properties of the cryptobox can be accessed by this class.
'''
def __init__(self):
def __init__(self, config_file=None):
'''read config and fill class variables'''
CryptoBox.__init__(self)
CryptoBox.__init__(self, config_file)
#self.cbx_inheritance_test()
#print self.cbxPrefs.items()
@ -186,6 +198,7 @@ class CryptoBoxProps(CryptoBox):
if self.isDeviceAllowed(device):
self.containers.append(CryptoBoxContainer.CryptoBoxContainer(device, self))
def isDeviceAllowed(self, devicename):
"check if a device is white-listed for being used as cryptobox containers"
allowed = self.cbxPrefs["Main"]["AllowedDevices"]
@ -336,6 +349,11 @@ class CryptoBoxProps(CryptoBox):
except OSError:
return []
# choose an exit function
if __name__ == "__main__":
CryptoBox.errorExit = CryptoBox.errorExitProg
else:
CryptoBox.errorExit = CryptoBox.errorExitMod
if __name__ == "__main__":
cb = CryptoBox()

View file

@ -83,6 +83,19 @@ class CryptoBoxContainer:
def isMounted(self):
return os.path.ismount(self.__getMountPoint())
def getCapacity(self):
"""return the current capacity state of the volume
the result is a tuple of values in megabyte:
(size, available, used)
"""
info = os.statvfs(self.__getMountPoint())
return (
int(info.f_bsize*info.f_blocks/1024/1024),
int(info.f_bsize*info.f_bavail/1024/1024),
int(info.f_bsize*(info.f_blocks-info.f_bavail)/1024/1024))
def create(self, type, password=None):

View file

@ -1,6 +0,0 @@
this is the future plan for the cbx python classes, you can find the actual classes under ./doc (generated by happydoc)
Classes and Methods:
CryptoBoxContainer
getCapacity

View file

@ -44,6 +44,12 @@ def main():
" ***************** some functions ******************** "
def luks_tests(e):
# umount if necessary
try:
e.umount()
except "MountError":
pass
e.create(e.Types["luks"], "alt")
print "\tluks create:\tok"
@ -60,6 +66,8 @@ def luks_tests(e):
if e.isMounted(): print "\tluks mount:\tok"
else: print "\tluks mount:\tfailed"
print "\tCapacity (size, free, used) [MB]:\t%s" % (e.getCapacity(), )
try:
e.umount()
except "MountError":
@ -72,6 +80,12 @@ def luks_tests(e):
def plain_tests(e):
# umount if necessary
try:
e.umount()
except "MountError":
pass
e.create(e.Types["plain"])
print "\tplain create:\tok"
@ -85,6 +99,8 @@ def plain_tests(e):
if e.isMounted(): print "\tplain mount:\tok"
else: print "\tplain mount:\tfailed"
print "\tCapacity (size, free, used) [MB]:\t%s" % (e.getCapacity(), )
try:
e.umount()
except "MountError":

View file

@ -14,7 +14,7 @@ class CryptoBoxPropsDeviceTests(unittest.TestCase):
self.assertTrue(self.cb.isDeviceAllowed("/dev/usb/../loop1"))
def testDeniedDevices(self):
'''isDeviceAllowed should fail with not explecitly allowed devices'''
'''isDeviceAllowed should fail with not explicitly allowed devices'''
self.assertFalse(self.cb.isDeviceAllowed("/dev/hda"))
self.assertFalse(self.cb.isDeviceAllowed("/dev/loopa/../hda"))
self.assertFalse(self.cb.isDeviceAllowed("/"))
@ -22,56 +22,98 @@ class CryptoBoxPropsDeviceTests(unittest.TestCase):
class CryptoBoxPropsConfigTests(unittest.TestCase):
'''test here if everything with the config turns right'''
import filehandling
import os
import CryptoBox
files = { "configFile" : "cbox-test.conf",
"nameDBFile" : "cryptobox_names.db",
"logFile" : "cryptobox.log",
"tmpdir" : "cryptobox-mnt" }
files = {
"configFileOK" : "cbox-test_ok.conf",
"configFileBroken" : "cbox-test_broken.conf",
"nameDBFile" : "cryptobox_names.db",
"logFile" : "cryptobox.log",
"tmpdir" : "cryptobox-mnt" }
tmpdirname = ""
filenames = {}
configContent = """
[Main]
AllowedDevices = /dev/loop
DefaultVolumePrefix = "Data "
DataDir = /tmp
NameDatabase = cryptobox_names.db
[System]
User = 1000
Group = 1000
MountParentDir = /tmp/mnt
DefaultCipher = aes-cbc-essiv:sha256
[Log]
Level = debug
Facility = file
Destination = /tmp/cryptobox.log
[Programs]
blkid = /sbin/blkid
cryptsetup = /sbin/cryptsetup
"""
configContentOK = """
[Main]
AllowedDevices = /dev/loop
DefaultVolumePrefix = "Data "
DataDir = %s
NameDatabase = cryptobox_names.db
[System]
User = 1000
Group = 1000
MountParentDir = %s/mnt
DefaultCipher = aes-cbc-essiv:sha256
[Log]
Level = debug
Destination = file
#Details = %s/cryptobox.log
Details = /tmp/cryptobox.log
[Programs]
blkid = /sbin/blkid
cryptsetup = /sbin/cryptsetup
super = /usr/bin/super
CryptoBoxRootActions = CryptoBoxRootActions"""
configContentBroken = """
[Main]
AllowedDevices = /dev/loop
DefaultVolumePrefix = "Data "
#DataDir = %s
NameDatabase = cryptobox_names.db
[System]
User = 1000
Group = 1000
MountParentDir = %s/mnt
DefaultCipher = aes-cbc-essiv:sha256
[Log]
Level = debug
Destination = file
#Details = %s/cryptobox.log
Details = /tmp/cryptobox.log
[Programs]
blkid = /sbin/blkid
cryptsetup = /sbin/cryptsetup
super = /usr/bin/super
CryptoBoxRootActions = CryptoBoxRootActions"""
def setUp(self):
'''generate all files in tmp and remember the names'''
import tempfile
os = self.os
self.tmpdirname = self.filehandling.gen_temp_dir(self.files["tmpdir"])
os.chdir(self.tmpdirname)
self.tmpdirname = tempfile.mkdtemp(prefix="cbox-")
for file in self.files.keys():
#TODO: files are not really created in tmpdirname
self.filenames[file] = self.filehandling.gen_temp_file(self.files[file])
self.filenames[file] = os.path.join(self.tmpdirname, self.files[file])
cf = open(self.filenames["configFileOK"], "w")
cf.write(self.configContentOK % (self.tmpdirname, self.tmpdirname, self.tmpdirname))
cf.close()
cf = open(self.filenames["configFileBroken"], "w")
cf.write(self.configContentBroken % (self.tmpdirname, self.tmpdirname, self.tmpdirname))
cf.close()
def tearDown(self):
'''remove the created tmpfiles'''
os = self.os
os.chdir(self.tmpdirname)
# remove temp files
for file in self.filenames.values():
if os.path.exists(file):
#os.remove(file)
pass
os.remove(file)
# remove temp dir
os.rmdir(self.tmpdirname)
def testConfigFile(self):
'''testConfigFile TODO'''
def testConfigInit(self):
'''Check various branches of config file loading'''
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,"/invalid/path/to/config/file")
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,"/etc/shadow")
self.CryptoBox.CryptoBoxProps()
self.CryptoBox.CryptoBoxProps(self.filenames["configFileOK"])
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,[])
self.assertRaises("ConfigError", self.CryptoBox.CryptoBoxProps,self.filenames["configFileBroken"])
# TODO: check details of different ConfigError-exceptions
# TODO: use different kind of broken setups ...
self.assertTrue(1)