plugin interface implemented
example plugins added: date and network moved "logs" to plugins
This commit is contained in:
parent
5af79f90b6
commit
dba8ca79fd
27 changed files with 483 additions and 174 deletions
|
@ -26,6 +26,9 @@ class CryptoBox:
|
|||
|
||||
put things like logging, conf and oter stuff in here,
|
||||
that might be used by more classes, it will be passed on to them'''
|
||||
|
||||
VERSION = "0.3~1"
|
||||
|
||||
def __init__(self, config_file=None):
|
||||
import CryptoBoxSettings
|
||||
self.log = self.__getStartupLogger()
|
||||
|
@ -141,13 +144,14 @@ class CryptoBoxProps(CryptoBox):
|
|||
return []
|
||||
try:
|
||||
fd = open(log_file, "r")
|
||||
if maxSize: content = fd.readlines(maxSize)
|
||||
else: content = fd.readlines()
|
||||
if maxSize: fd.seek(-maxSize, 2) # seek relative to the end of the file
|
||||
content = fd.readlines()
|
||||
fd.close()
|
||||
except IOError:
|
||||
self.log.warn("failed to read the log file (%s)" % log_file)
|
||||
return []
|
||||
if lines: content = content[-lines:]
|
||||
content.reverse()
|
||||
return content
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,15 @@ class CryptoBoxError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class CBPluginError(CryptoBoxError):
|
||||
"""should be raised for plugin specific problems"""
|
||||
|
||||
|
||||
class CBPluginActionError(CBPluginError):
|
||||
"""should be raised when a plugin action failed"""
|
||||
pass
|
||||
|
||||
|
||||
class CBConfigError(CryptoBoxError):
|
||||
"""any kind of error related to the configuration of a cryptobox"""
|
||||
pass
|
||||
|
|
|
@ -171,6 +171,7 @@ NameDatabase = fileWriteable(default="/var/cache/cryptobox/volumen_names.db")
|
|||
TemplateDir = directoryExists(default="/usr/share/cryptobox/template")
|
||||
LangDir = directoryExists(default="/usr/share/cryptobox/lang")
|
||||
DocDir = directoryExists(default="/usr/share/doc/cryptobox/html")
|
||||
PluginDir = directoryExists(default="/usr/share/cryptobox/plugins")
|
||||
|
||||
[Log]
|
||||
Level = option("debug", "info", "warn", "error", default="warn")
|
||||
|
|
76
pythonrewrite/bin2/Plugins.py
Normal file
76
pythonrewrite/bin2/Plugins.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
# $Id$
|
||||
|
||||
import imp
|
||||
import os
|
||||
import logging
|
||||
|
||||
|
||||
class PluginManager:
|
||||
"""manage available plugins"""
|
||||
|
||||
def __init__(self, plugin_dirs=None):
|
||||
self.log = logging.getLogger("CryptoBox")
|
||||
if hasattr(plugin_dirs, "__iter__"):
|
||||
self.plugin_dirs = [os.path.abspath(dir) for dir in plugin_dirs]
|
||||
else:
|
||||
self.plugin_dirs = [os.path.abspath(plugin_dirs)]
|
||||
|
||||
|
||||
def allPlugins(self):
|
||||
for plfile in self.__getPluginFiles():
|
||||
yield os.path.basename(plfile)[:-3]
|
||||
|
||||
|
||||
def getPlugin(self, name):
|
||||
for plfile in self.__getPluginFiles():
|
||||
if name == os.path.basename(plfile)[:-3]:
|
||||
return imp.load_source(name, plfile)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def getTemplateFileName(self, plname, template_name):
|
||||
"""return the name of the template file, if it is part of the mentioned plugin
|
||||
"""
|
||||
result = [os.path.join(os.path.dirname(cur_file), template_name + ".cs")
|
||||
for cur_file in self.__getPluginFiles()
|
||||
if plname == os.path.basename(cur_file)[:-3]]
|
||||
for templ_file in result:
|
||||
if os.access(templ_file, os.R_OK) and os.path.isfile(templ_file):
|
||||
return templ_file
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def loadLanguageData(self, hdf, lang="en"):
|
||||
for plfile in self.__getPluginFiles():
|
||||
langdir = os.path.join(os.path.dirname(plfile), "lang")
|
||||
selected_langfile = os.path.join(langdir, lang + ".hdf")
|
||||
default_langfile = os.path.join(langdir, "en.hdf")
|
||||
for langfile in (selected_langfile, default_langfile):
|
||||
if os.access(langfile, os.R_OK):
|
||||
self.log.debug("Loading plugin language file: %s" % langfile)
|
||||
hdf.readFile(langfile)
|
||||
break
|
||||
else:
|
||||
self.log.debug("Couldn't find a plugin language file (%s)" % default_langfile)
|
||||
|
||||
|
||||
def __getPluginFiles(self):
|
||||
result = []
|
||||
for dir in [os.path.abspath(e) for e in self.plugin_dirs if os.access(e, os.R_OK) and os.path.isdir(e)]:
|
||||
for plname in [f for f in os.listdir(dir)]:
|
||||
pldir = os.path.join(dir, plname)
|
||||
plfile = os.path.join(pldir, plname + ".py")
|
||||
if os.path.isfile(plfile) and os.access(plfile, os.R_OK):
|
||||
result.append(plfile)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
x = PluginManager("../plugins")
|
||||
for a in x.allPlugins():
|
||||
print "Plugin: %s" % a
|
||||
print x.getPlugin(a).getStatus()
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
import CryptoBoxContainer
|
||||
|
||||
## useful constant for many functions
|
||||
## useful constant for some functions
|
||||
CONT_TYPES = CryptoBoxContainer.CryptoBoxContainer.Types
|
||||
|
||||
class WebInterfaceDataset(dict):
|
||||
|
@ -16,6 +16,31 @@ class WebInterfaceDataset(dict):
|
|||
self.__setCryptoBoxState()
|
||||
|
||||
|
||||
def setPluginState(self, plugins):
|
||||
for pl in plugins.allPlugins():
|
||||
self["Data.Status.Modules." + pl] = plugins.getPlugin(pl).getStatus(self.cbox)
|
||||
|
||||
|
||||
def setCurrentDiskState(self, device):
|
||||
for container in self.cbox.getContainerList():
|
||||
if container.getDevice() == device:
|
||||
isEncrypted = (container.getType() == CONT_TYPES["luks"]) and 1 or 0
|
||||
isPlain = (container.getType() == CONT_TYPES["plain"]) and 1 or 0
|
||||
isMounted = container.isMounted() and 1 or 0
|
||||
self["Data.CurrentDisk.device"] = container.getDevice()
|
||||
self["Data.CurrentDisk.name"] = container.getName()
|
||||
self["Data.CurrentDisk.encryption"] = isEncrypted
|
||||
self["Data.CurrentDisk.plaintext"] = isPlain
|
||||
self["Data.CurrentDisk.active"] = isMounted
|
||||
if isMounted:
|
||||
(size, avail, used) = container.getCapacity()
|
||||
percent = used / size
|
||||
self["Data.CurrentDisk.capacity.used"] = used
|
||||
self["Data.CurrentDisk.capacity.free"] = avail
|
||||
self["Data.CurrentDisk.capacity.size"] = size
|
||||
self["Data.CurrentDisk.capacity.percent"] = percent
|
||||
|
||||
|
||||
def __setConfigValues(self):
|
||||
self["Settings.TemplateDir"] = os.path.abspath(self.prefs["Locations"]["TemplateDir"])
|
||||
self["Settings.LanguageDir"] = os.path.abspath(self.prefs["Locations"]["LangDir"])
|
||||
|
@ -26,6 +51,7 @@ class WebInterfaceDataset(dict):
|
|||
|
||||
|
||||
def __setCryptoBoxState(self):
|
||||
self["Data.Version"] = self.cbox.VERSION
|
||||
avail_counter = 0
|
||||
active_counter = 0
|
||||
for container in self.cbox.getContainerList():
|
||||
|
@ -45,26 +71,6 @@ class WebInterfaceDataset(dict):
|
|||
## TODO: open issues: Data.Config.AdminPasswordIsSet
|
||||
|
||||
|
||||
def setCurrentDiskState(self, device):
|
||||
for container in self.cbox.getContainerList():
|
||||
if container.getDevice() == device:
|
||||
isEncrypted = (container.getType() == CONT_TYPES["luks"]) and 1 or 0
|
||||
isPlain = (container.getType() == CONT_TYPES["plain"]) and 1 or 0
|
||||
isMounted = container.isMounted() and 1 or 0
|
||||
self["Data.CurrentDisk.device"] = container.getDevice()
|
||||
self["Data.CurrentDisk.name"] = container.getName()
|
||||
self["Data.CurrentDisk.encryption"] = isEncrypted
|
||||
self["Data.CurrentDisk.plaintext"] = isPlain
|
||||
self["Data.CurrentDisk.active"] = isMounted
|
||||
|
||||
if isMounted:
|
||||
(size, avail, used) = container.getCapacity()
|
||||
percent = used / size
|
||||
self["Data.CurrentDisk.capacity.used"] = used
|
||||
self["Data.CurrentDisk.capacity.free"] = avail
|
||||
self["Data.CurrentDisk.capacity.size"] = size
|
||||
self["Data.CurrentDisk.capacity.percent"] = percent
|
||||
|
||||
def __getLanguageName(self, lang):
|
||||
import neo_cgi, neo_util, neo_cs
|
||||
hdf_path = os.path.join(self.prefs["Locations"]["LangDir"], lang + ".hdf")
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import CryptoBox
|
||||
import WebInterfaceDataset
|
||||
import re
|
||||
from Plugins import PluginManager
|
||||
from CryptoBoxExceptions import *
|
||||
|
||||
class WebInterfaceSites:
|
||||
'''
|
||||
|
@ -14,6 +16,16 @@ class WebInterfaceSites:
|
|||
self.log = logging.getLogger("CryptoBox")
|
||||
self.prefs = self.cbox.prefs
|
||||
self.__resetDataset()
|
||||
self.plugins = PluginManager(self.prefs["Locations"]["PluginDir"])
|
||||
self.__exposePlugins()
|
||||
|
||||
|
||||
def __exposePlugins(self):
|
||||
for plname in self.plugins.allPlugins():
|
||||
self.log.info("Plugin '%s' loaded" % plname)
|
||||
## this should be the "easiest" way to expose all modules as URLs
|
||||
setattr(self, "module_" + plname, self.return_module_action(plname))
|
||||
setattr(getattr(self, "module_" + plname), "exposed", True)
|
||||
|
||||
|
||||
def __resetDataset(self):
|
||||
|
@ -65,12 +77,6 @@ class WebInterfaceSites:
|
|||
return self.__render("show_status")
|
||||
|
||||
|
||||
def config(self,weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
pass
|
||||
|
||||
|
||||
def doc(self,page="",weblang=""):
|
||||
'''prints the offline wikipage
|
||||
'''
|
||||
|
@ -86,22 +92,11 @@ class WebInterfaceSites:
|
|||
self.dataset["Data.Doc.Page"] ="CryptoBoxUser"
|
||||
|
||||
return self.__render("show_doc")
|
||||
|
||||
|
||||
|
||||
def system(self, shutdowntype="", weblang=""):
|
||||
# TODO: check weblang
|
||||
def system(self, weblang=""):
|
||||
self.__resetDataset()
|
||||
self.__setWebLang(weblang)
|
||||
if shutdowntype == "reboot":
|
||||
self.dataset["Data.Success"] = "ReBoot"
|
||||
self.dataset["Data.Redirect.Action"] = "show_status"
|
||||
self.dataset["Data.Redirect.Delay"] = "180"
|
||||
self.log.info("TODO: call function for system reboot")
|
||||
elif shutdowntype == "poweroff":
|
||||
self.dataset["Data.Success"] = "PowerOff"
|
||||
self.log.info("TODO: call function for system shutdown")
|
||||
else:
|
||||
self.log.warn("This shutdown-mode (%s) is not supported." % shutdowntype)
|
||||
return self.__render("form_system")
|
||||
|
||||
|
||||
|
@ -315,7 +310,27 @@ class WebInterfaceSites:
|
|||
return self.__render("show_status")
|
||||
return self.__render("show_volume")
|
||||
|
||||
|
||||
|
||||
def return_module_action(self, module):
|
||||
def handler(**args):
|
||||
self.__resetDataset()
|
||||
try:
|
||||
self.__setWebLang(args["weblang"])
|
||||
del args["weblang"]
|
||||
except KeyError:
|
||||
pass
|
||||
plugin = self.plugins.getPlugin(module)
|
||||
try:
|
||||
nextTemplate = plugin.doAction(self.cbox, **args)
|
||||
except CBPluginActionError, errMsg:
|
||||
self.log.debug(errMsg)
|
||||
self.dataset["Data.Warning"] = errMsg
|
||||
nextTemplate = "empty"
|
||||
plugin.prepareForm(self.dataset, self.cbox)
|
||||
return self.__render(nextTemplate, module)
|
||||
return handler
|
||||
|
||||
|
||||
'''
|
||||
## DONE: these functions are pythonized
|
||||
#################### show_log #######################
|
||||
|
@ -403,7 +418,7 @@ class WebInterfaceSites:
|
|||
return False
|
||||
|
||||
|
||||
def __render(self, template):
|
||||
def __render(self, template, module=None):
|
||||
'''renders from clearsilver templates and returns the resulting html
|
||||
|
||||
Gets a dictionary with all settings, nessessary for rendering.
|
||||
|
@ -411,7 +426,6 @@ class WebInterfaceSites:
|
|||
object, that calls this render method. This might be bloat but
|
||||
this way the render method has always a complete, actual set of values.
|
||||
'''
|
||||
|
||||
import os
|
||||
try:
|
||||
import neo_cgi, neo_util, neo_cs
|
||||
|
@ -421,7 +435,11 @@ class WebInterfaceSites:
|
|||
sys.stderr.write(errorMsg)
|
||||
raise ImportError, errorMsg
|
||||
|
||||
self.dataset["Data.Action"] = template
|
||||
module_cs_file = False
|
||||
if module:
|
||||
module_cs_file = self.plugins.getTemplateFileName(module, template)
|
||||
default_cs_file = os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs")
|
||||
self.dataset["Data.TemplateFile"] = module_cs_file or default_cs_file
|
||||
self.log.info("rendering site: " + template)
|
||||
|
||||
cs_path = os.path.join(self.prefs["Locations"]["TemplateDir"], "main.cs")
|
||||
|
@ -435,11 +453,16 @@ class WebInterfaceSites:
|
|||
log.error("Couldn't read language file: %s" % hdf_path)
|
||||
return "Couldn't read language file: %s" % hdf_path
|
||||
|
||||
## add the current state of the plugins to the hdf dataset
|
||||
self.dataset.setPluginState(self.plugins)
|
||||
|
||||
hdf = neo_util.HDF()
|
||||
hdf.readFile(hdf_path)
|
||||
self.log.debug(self.dataset)
|
||||
for key in self.dataset.keys():
|
||||
hdf.setValue(key,str(self.dataset[key]))
|
||||
## load languaga data of plugins
|
||||
self.plugins.loadLanguageData(hdf, lang=self.dataset["Settings.Language"])
|
||||
cs = neo_cs.CS(hdf)
|
||||
cs.parseFile(cs_path)
|
||||
return cs.render()
|
||||
|
@ -462,6 +485,7 @@ class WebInterfaceSites:
|
|||
test.exposed = True
|
||||
|
||||
|
||||
|
||||
"""
|
||||
## TODO: check this before anything else
|
||||
if self.cbox.getAvailableDocLanguages():
|
||||
|
|
|
@ -32,6 +32,11 @@ LangDir = ../lang
|
|||
#DocDir = /usr/share/doc/cryptobox/html
|
||||
DocDir = ../doc/html
|
||||
|
||||
# path to the plugin directory
|
||||
#PluginDir = /usr/share/cryptobox/plugins
|
||||
PluginDir = ../plugins
|
||||
|
||||
|
||||
|
||||
[Log]
|
||||
# possible values are "debug", "info", "warn" and "error" or numbers from
|
||||
|
|
|
@ -48,6 +48,7 @@ MountParentDir = %s
|
|||
TemplateDir = ../templates
|
||||
LangDir = ../lang
|
||||
DocDir = ../doc/html
|
||||
PluginDir = ../plugins
|
||||
[Log]
|
||||
Level = debug
|
||||
Destination = file
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue