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:
parent
bb16749b81
commit
707fb71476
5 changed files with 168 additions and 85 deletions
|
@ -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,12 +143,10 @@ 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
|
||||
|
@ -164,6 +154,28 @@ class CryptoBox:
|
|||
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]
|
||||
# RFC: shouldn't we move all useful functions of CryptoBoxProps to CryptoBox? [l]
|
||||
class CryptoBoxProps(CryptoBox):
|
||||
|
@ -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()
|
||||
|
|
|
@ -85,6 +85,19 @@ class CryptoBoxContainer:
|
|||
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):
|
||||
if type == self.Types["luks"]:
|
||||
self.__createLuks(password)
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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":
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue