Commit 0f0c92ba authored by Devaev Maxim's avatar Devaev Maxim

Added short functions for logging, split config loading on two stages, daemon…

Added short functions for logging, split config loading on two stages, daemon module, main() with getopt and interactive mode of service
parent f4daeb3e
# -*- coding: utf-8 -*-
import sys
import syslog
import getopt
from settingsd import const
from settingsd import config
from settingsd import logger
from settingsd import validators
from settingsd import application
#from settingsd import daemon # TODO
##### Private methods #####
def help() :
print ( "Usage: %s [options]\n"
"Options:\n"
"\t-h, --help -- Print this text\n"
"\t-v, --version -- Print version and license info\n"
"\t--log-level=<0|1|2> -- Log level, replace value from config\n"
"\t--use-syslog=<yes|no> -- Force enable or disable useage of syslog\n"
"\t--bus-type=<system|session> -- Use system or session bus, replace value from config\n"
"\t-d, --daemon -- Run application as daemon, by default using interactive mode\n"
"\t-k, --kill -- Kill daemon process" % (const.MY_NAME) )
def version() :
print "%s version %s" % (const.MY_NAME, const.VERSION)
##### Main ######
if __name__ == "__main__" :
app = application.Application()
app.exec_()
log_level = None
use_syslog_flag = None
bus_type = None
daemon_mode_flag = False
try :
(opts_list, args_list) = getopt.getopt(sys.argv[1:], "hdk", ( "help", "version",
"log-level=", "use-syslog=", "bus-type=", "daemon", "kill" ))
for (opts_list_item, args_list_item) in opts_list :
if opts_list_item in ("-h", "--help") :
help()
elif opts_list_item in ("-v", "--version") :
version()
elif opts_list_item in ("--log-level") :
try :
log_level = validators.validRange(int(args_list_item), const.ALL_LOG_LEVELS_LIST)
except Exception, err1 :
print "Incorrect option \"%s\": %s" % (opts_list_item, str(err1))
sys.exit(1)
elif opts_list_item in ("--use-syslog") :
try :
use_syslog_flag = validators.validBool(args_list_item)
except Exception, err1 :
print "Incorrect option \"%s\": %s" % (opts_list_item, str(err1))
elif opts_list_item in ("--bus-type") :
try :
bus_type = validators.validRange(args_list_item, const.ALL_BUS_TYPES_LIST)
except Exception, err1 :
print "Incorrect option \"%s\": %s" % (opts_list_item, str(err1))
sys.exit(1)
elif opts_list_item in ("-d", "--daemon") :
daemon_mode_flag = True
elif opts_list_item in ("-k", "--kill") :
pass # TODO
else :
print "Unknown option \"%s\"" % (opts_list_item)
except Exception, err1 :
print "Bad command line options: %s" % (str(err1))
#####
if not daemon_mode_flag :
app = application.Application()
try :
app.loadApplicationConfigs()
except :
logger.error("Initialization error")
sys.exit(1)
if bus_type != None :
config.setValue(const.MY_NAME, "bus_type", bus_type)
if log_level != None :
config.setValue(const.MY_NAME, "log_level", log_level)
if use_syslog_flag :
syslog.openlog(const.MY_NAME, syslog.LOG_PID, syslog.LOG_USER)
config.setValue(const.RUNTIME_NAME, "use_syslog", True)
try :
app.loadModules()
app.loadServicesConfigs()
app.initBus()
app.initServices()
logger.info("Initialized")
except :
logger.error("Initialization error")
sys.exit(1)
try :
app.runLoop()
except (SystemExit, KeyboardInterrupt) :
try :
app.closeServices()
except :
logger.error("Critical error on services closing, abort all processes and go boom")
app.quitLoop()
logger.info("Closed")
except :
logger.error("Runtime error, trying to close services")
logger.attachException()
try :
app.closeServices()
except :
logger.error("Critical error on services closing, abort all processes and go boom")
app.quitLoop()
logger.info("Closed")
sys.exit(1)
else :
print "TODO"
......@@ -19,7 +19,7 @@ class Application(object) :
def __init__(self) :
object.__init__(self)
self._bus_name = None
#####
self._modules_list = []
self._services_dict = {}
......@@ -29,30 +29,13 @@ class Application(object) :
### Public ###
def exec_(self) :
self.init()
logger.message(logger.INFO_MESSAGE, "Initialized")
try :
self.run()
except KeyboardInterrupt :
self.close()
logger.message(logger.INFO_MESSAGE, "Closed")
### Private ###
def init(self) :
self.loadModules()
self.loadConfigs()
self.initBus()
self.initServices()
def run(self) :
def runLoop(self) :
logger.verbose("Running GObject loop...")
self._main_loop.run()
def close(self) :
self.closeServices()
def quitLoop(self) :
self._main_loop.quit()
logger.verbose("GObject loop closed")
def loadModules(self) :
sys.path.append(const.FUNCTIONS_DIR)
......@@ -62,46 +45,70 @@ class Application(object) :
for module_name in [ item[:-3] for item in os.listdir(modules_path_list_item) if item.endswith(".py") ] :
try :
self._modules_list.append(__import__(module_name, globals(), locals(), [""]))
except Exception :
logger.message(logger.ERROR_MESSAGE, "Import error on module \"%s\"" % (module_name))
except :
logger.error("Import error on module \"%s\"" % (module_name))
logger.attachException()
continue
self._services_dict[self._modules_list[-1].Service.serviceName()] = {
"service_class" : self._modules_list[-1].Service,
"service" : None
}
logger.verbose("Loaded module: %s" % (module_name))
sys.path.remove(const.FUNCTIONS_DIR)
sys.path.remove(const.ACTIONS_DIR)
def loadConfigs(self) :
def loadApplicationConfigs(self) :
config.loadConfigs(only_sections_list = (const.MY_NAME,))
def loadServicesConfigs(self) :
for service_name in self._services_dict.keys() :
service_options_list = list(self._services_dict[service_name]["service_class"].optionsList())
service_options_list.append((service_name, "enabled", "no", validators.validBool))
for service_options_list_item in service_options_list :
config.setValue(*service_options_list_item)
try :
config.setValue(*service_options_list_item)
except :
logger.error("Error on set options tuple %s" % (str(service_options_list_item)))
logger.attachException()
config.loadConfig()
config.loadConfigs(exclude_sections_list = (const.MY_NAME,))
def initBus(self) :
if config.value(const.MY_NAME, "bus_type") == const.BUS_TYPE_SYSTEM :
bus = dbus.SystemBus()
else :
bus = dbus.SessionBus()
self._bus_name = dbus.service.BusName(config.value(const.MY_NAME, "service_name"), bus = bus)
config.setValue(const.RUNTIME_NAME, "bus_name", self._bus_name)
bus_type = config.value(const.MY_NAME, "bus_type")
service_name = config.value(const.MY_NAME, "service_name")
try :
config.setValue(const.RUNTIME_NAME, "bus_name", dbus.service.BusName(service_name,
( dbus.SystemBus() if bus_type == const.BUS_TYPE_SYSTEM else dbus.SessionBus() )))
except :
logger.error("Could not connect to D-Bus \"%s\"" % (bus_type))
logger.attachException()
raise
logger.verbose("Connected to D-Bus \"%s\" as \"%s\"" % (bus_type, service_name))
def initServices(self) :
for service_name in self._services_dict.keys() :
if config.value(service_name, "enabled") :
self._services_dict[service_name]["service"] = self._services_dict[service_name]["service_class"]()
self._services_dict[service_name]["service"].initService()
try :
self._services_dict[service_name]["service"] = self._services_dict[service_name]["service_class"]()
self._services_dict[service_name]["service"].initService()
except :
logger.error("Cannot initialize service \"%s\"" % (service_name))
logger.attachException()
def closeServices(self) :
for service_name in self._services_dict.keys() :
if self._services_dict[service_name]["service"] != None :
self._services_dict[service_name]["service"].closeService()
del self._services_dict[service_name]["service"]
try :
self._services_dict[service_name]["service"].closeService()
del self._services_dict[service_name]["service"]
except :
logger.error("Cannot close service \"%s\"" % (service_name))
logger.attachException()
self._services_dict[service_name]["service"] = None
......@@ -18,8 +18,8 @@ ConfigDictObject = {
"log_level" : (const.DEFAULT_LOG_LEVEL, ( lambda arg : validators.validRange(int(arg), const.ALL_LOG_LEVELS_LIST) ))
},
const.RUNTIME_NAME : {
"bus_name" : None,
"use_syslog" : False
"bus_name" : (None, None),
"use_syslog" : (False, None)
}
}
......@@ -48,7 +48,11 @@ def value(section, option) :
def validator(section, option) :
return ConfigDictObject[section][option][1]
def loadConfig() :
def loadConfigs(only_sections_list = (), exclude_sections_list = ()) :
only_sections_list = list(only_sections_list)
exclude_sections_list = list(exclude_sections_list)
exclude_sections_list.append(const.RUNTIME_NAME)
for config_files_list_item in os.listdir(const.CONFIGS_DIR) :
if not config_files_list_item.endswith(const.CONFIG_FILE_POSTFIX) :
continue
......@@ -57,7 +61,7 @@ def loadConfig() :
config_parser.read(os.path.join(const.CONFIGS_DIR, config_files_list_item))
for section in config_parser.sections() :
if section == const.RUNTIME_NAME :
if (len(only_sections_list) != 0 and not section in only_sections_list) or section in exclude_sections_list :
continue
for option in config_parser.options(section):
......
......@@ -5,6 +5,8 @@
MY_NAME = "settingsd"
RUNTIME_NAME = "runtime"
VERSION = "0.1"
FUNCTIONS_DIR = "functions"
ACTIONS_DIR = "actions"
CONFIGS_DIR = "configs"
......
# -*- coding: utf-8 -*-
import os
import signal
import errno
import resource
import logger
##### Private methods #####
def pidOfPythonProc(proc_name, uid = 0) :
for proc_list_item in os.listdir("/proc") :
try :
proc_pid = int(proc_list_item)
except :
continue
cmdline_file_path = os.path.join("/proc", proc_list_item, "cmdline")
if os.stat(cmdline_file_path).st_mode != uid :
continue
cmdline_file = open(cmdline_file_path)
cmdline_list = cmdline_file.read().split("\0")
if len(cmdline_list) >= 2 and os.path.basename(cmdline_list[1]) == proc_name :
cmdline_file.close()
return proc_pid
cmdline_file.close()
return None
def maxFd() :
max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
if max_fd == resource.RLIM_INFINITY :
max_fd = 1024
try :
max_fd = os.sysconf("SC_OPEN_MAX")
except ValueError :
pass
if max_fd < 0 :
max_fd = 1024
return max_fd
def closeFd(fd, retries_count = 5) :
for count in xrange(retries_count) :
try :
os.close(fd)
except OSError, err1 :
if err1.errno != errno.EBADF :
continue
break
##### Public methods #####
def startDaemon(init_function, close_function, work_dir_path = None, umask = None) :
pid = os.fork()
if pid > 0 :
try :
os.waitpid(pid, 0)
except OSError :
pass
os._exit(0)
elif pid == 0 :
logger.verbose("First fork() to %d as session lead" % (os.getpid()))
os.setsid()
pid = os.fork()
if pid > 0 :
os._exit(0)
elif pid == 0 :
logger.verbose("Second fork() to %d as main process" % (os.getpid()))
if work_dir_path != None :
os.chdir(work_dir_path)
logger.verbose("New working directory: %s" % (work_dir_path))
if umask != None :
os.umask(umask)
logger.verbose("Accapted new umask: %.3o" % (umask))
for fd in xrange(maxFd()) :
closeFd(fd)
null_fd = os.open("/dev/null", os.O_RDWR)
for fd in (0, 1, 2) :
os.dup2(null_fd, fd)
try :
init_function()
except (SystemExit, KeyboardInterrupt) :
close_function()
except :
try :
close_function()
except :
pass
os._exit(1) # FIXME
else :
os._exit(1) # FIXME
else :
os._exit(1) # FIXME
def killDaemon() :
pid = pidOfPythonProc("main.py", os.getuid()) # FIXME
if pid != None :
os.kill(pid, signal.SIGTERM)
else :
logger.error("Cannot determine a daemon process of \"%s\"" % ("main.py")) # FIXME
......@@ -33,7 +33,31 @@ class UnknownMessageType(Exception) :
##### Public methods #####
def message(message_type, message) :
def error(message) :
log(ERROR_MESSAGE, message)
def info(message) :
log(INFO_MESSAGE, message)
def notice(message) :
log(NOTICE_MESSAGE, message)
def warning(message) :
log(WARNING_MESSAGE, message)
def verbose(message) :
log(VERBOSE_MESSAGE, message)
def debug(message) :
log(DEBUG_MESSAGE, message)
def attachException(message_type = ERROR_MESSAGE) :
for line in traceback.format_exc().splitlines() :
log(message_type, line)
##### Private methods #####
def log(message_type, message) :
if not message_type in ALL_MESSAGES_LIST :
raise UnknownMessageType("Message type \"%d\" not in list %s" % (message_type, ALL_MESSAGES_LIST))
......@@ -43,10 +67,6 @@ def message(message_type, message) :
print >> sys.stderr, const.MY_NAME, message
if config.value(const.RUNTIME, "use_syslog") :
if config.value(const.RUNTIME_NAME, "use_syslog") :
syslog.syslog(message_type[1], message)
def attachException(message_type = ERROR_MESSAGE) :
for line in traceback.format_exc().splitlines() :
message(message_type, line)
......@@ -83,8 +83,8 @@ def tracer(function) :
def wrapper(self, *args_list, **kwargs_dict) :
return_value = function(self, *args_list, **kwargs_dict)
if config.value(const.MY_NAME, "log_level") == const.LOG_LEVEL_DEBUG :
logger.message(logger.DEBUG_MESSAGE, "Called \"%s::%s\" with args (%s, %s) --> %s" % (
self.__class__.__name__, function.__name__, str(args_list), str(kwargs_dict), str(return_value) ))
logger.debug("Called \"%s::%s\" with args (%s, %s) --> %s" % (self.__class__.__name__, function.__name__,
str(args_list), str(kwargs_dict), str(return_value) ))
return return_value
wrapper.__name__ = function.__name__
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment