1
0
Fork 0

various fixes

This commit is contained in:
Jan Vcelak 2011-11-10 18:38:47 +01:00
parent 0932642421
commit 67e736a7f6
15 changed files with 447 additions and 48 deletions

2
AUTHORS Normal file
View file

@ -0,0 +1,2 @@
Phil Knirsch
Jan Včelák

View file

@ -1,29 +0,0 @@
#
# Author: Jan Vcelak <jvcelak@redhat.com>
#
import controller
import interfaces
def export(*args, **kwargs):
"""Decorator, use to mark exportable methods."""
def wrapper(method):
method.export_params = [ args, kwargs ]
return method
return wrapper
def register_exporter(instance):
if not isinstance(instance, interfaces.IExporter):
raise Exception()
ctl = controller.ExportsController.get_instance()
return ctl.register_exporter(instance)
def register_object(instance):
if not isinstance(instance, interfaces.IExportable):
raise Exception()
ctl = controller.ExportsController.get_instance()
return ctl.register_object(instance)
def run():
ctl = controller.ExportsController.get_instance()
return ctl.run()

View file

@ -1,14 +0,0 @@
#
# Author: Jan Vcelak <jvcelak@redhat.com>
#
class IExportable(object):
pass
class IExporter(object):
def export(self, method, in_signature, out_signature):
# to be overriden by concrete implementation
raise NotImplemented()
def serve(self):
raise NotImplemented()

2
src/__init__.py Normal file
View file

@ -0,0 +1,2 @@
from logs import *
from daemon import *

View file

@ -1,3 +1,20 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
import os
import exports
import exports.dbus
@ -10,10 +27,9 @@ class Controller(exports.interfaces.IExportable):
def __init__(self):
super(self.__class__, self).__init__()
@exports.export("", "s")
@exports.export("", "b")
def start(self):
print "== inner start called =="
return "started (%s)" % self
return False
@exports.export("", "b")
def stop(self):

129
src/daemon.py Normal file
View file

@ -0,0 +1,129 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
import logs
import atexit
import os
import signal
import sys
log = logs.get("tuned")
CONFIG_FILE = "/etc/tuned/tuned.conf"
INIT_TIMEOUT = 3
class Daemon(object):
def __init__(self, config_file = None, debug = False):
log.info("initializing")
if config_file is None:
config_file = CONFIG_FILE
self._config_file = config_file
self._debug = debug
def daemonize(self):
log.debug("daemonizing")
parent_pid = os.getpid()
signal.signal(signal.SIGALRM, self._daemonize_handle_signal)
signal.signal(signal.SIGUSR1, self._daemonize_handle_signal)
signal.signal(signal.SIGUSR2, self._daemonize_handle_signal)
if self._daemonize_fork():
os.kill(parent_pid, signal.SIGUSR1)
log.debug("daemonizing done")
else:
os.kill(parent_pid, signal.SIGUSR2)
log.critical("daemonizing failed")
sys.exit(1)
signal.signal(signal.SIGALRM, signal.SIG_DFL)
signal.signal(signal.SIGUSR1, signal.SIG_DFL)
signal.signal(signal.SIGUSR2, signal.SIG_DFL)
def _daemonize_fork(self):
try:
pid = os.fork()
if pid > 0:
self._daemonize_wait()
assert False # unreachable
except OSError as e:
log.critical("fork: %s", str(e))
return false
os.chdir("/")
os.setsid()
os.umask(0)
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError as e:
log.cricital("fork: %s", str(e))
return false
si = file('/dev/null', 'r')
so = file('/dev/null', 'a+')
se = file('/dev/null', 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
return True
def _daemonize_wait(self):
signal.alarm(INIT_TIMEOUT)
while True:
signal.pause()
def _daemonize_handle_signal(self, signum, frame):
if signum == signal.SIGUSR1:
log.debug("daemonizing, got signal (success), exit")
sys.exit(0)
if signum == signal.SIGUSR2 or signum == signal.SIGALRM:
log.critical("daemonizing, signal %d (failure), exit" % signum)
sys.exit(1)
else:
log.warn("daemonizing, unknown signal %s, ignoring" % signum)
def run_controller(self):
pass
def run(self):
log.info("running")
import time
self._terminate = False
while not self._terminate:
time.sleep(1)
def terminate(self):
log.info("terminating")
self._terminate = True
def reload(self):
log.info("reloading")
pass
def cleanup(self):
# TODO: do we need it?
raise Exception()

42
src/exports/__init__.py Normal file
View file

@ -0,0 +1,42 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
import controller
import interfaces
def export(*args, **kwargs):
"""Decorator, use to mark exportable methods."""
def wrapper(method):
method.export_params = [ args, kwargs ]
return method
return wrapper
def register_exporter(instance):
if not isinstance(instance, interfaces.IExporter):
raise Exception()
ctl = controller.ExportsController.get_instance()
return ctl.register_exporter(instance)
def register_object(instance):
if not isinstance(instance, interfaces.IExportable):
raise Exception()
ctl = controller.ExportsController.get_instance()
return ctl.register_object(instance)
def run():
ctl = controller.ExportsController.get_instance()
return ctl.run()

View file

@ -1,5 +1,18 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# Author: Jan Vcelak <jvcelak@redhat.com>
# 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.
#
import interfaces

View file

@ -1,5 +1,18 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# Author: Jan Vcelak <jvcelak@redhat.com>
# 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.
#
from __future__ import absolute_import

27
src/exports/interfaces.py Normal file
View file

@ -0,0 +1,27 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
class IExportable(object):
pass
class IExporter(object):
def export(self, method, in_signature, out_signature):
# to be overriden by concrete implementation
raise NotImplemented()
def serve(self):
raise NotImplemented()

82
src/logs.py Normal file
View file

@ -0,0 +1,82 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
import atexit
import logging
import logging.handlers
import os
import os.path
__all__ = [ "get" ]
LOG_FILENAME = "/var/log/tuned/tuned.log"
LOG_FILE_MAXBYTES = 100*1000
LOG_FILE_COUNT = 2
def get(name = "tuned"):
return logging.getLogger(name)
class TunedLogger(logging.getLoggerClass()):
"""Custom tuned daemon logger class."""
_formatter = logging.Formatter("%(asctime)s %(levelname)-8s %(name)s: %(message)s")
_console_handler = None
_file_handler = None
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
self.setLevel(logging.INFO)
self.switch_to_console()
def set_level(self, level, default = logging.NOTSET):
"""Set logging level. The 'level' parameter can be str or logging module constant."""
if type(level) is str:
level = logging._levelNames.get(level.upper(), logging.NOTSET)
self.level = level
def switch_to_console(self):
self._setup_console_handler()
self.addHandler(self._console_handler)
self.removeHandler(self._file_handler)
def switch_to_file(self):
self._setup_file_handler()
self.addHandler(self._file_handler)
self.removeHandler(self._console_handler)
@classmethod
def _setup_console_handler(cls):
if cls._console_handler is not None:
return
cls._console_handler = logging.StreamHandler()
cls._console_handler.setFormatter(cls._formatter)
@classmethod
def _setup_file_handler(cls):
if cls._file_handler is not None:
return
log_directory = os.path.dirname(LOG_FILENAME)
if not os.path.exists(log_directory):
os.makedirs(log_directory)
cls._file_handler = logging.handlers.RotatingFileHandler(
LOG_FILENAME, maxBytes=LOG_FILE_MAXBYTES, backupCount=LOG_FILE_COUNT)
cls._file_handler.setFormatter(cls._formatter)
logging.setLoggerClass(TunedLogger)
atexit.register(logging.shutdown)

25
src/main.py Normal file
View file

@ -0,0 +1,25 @@
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
import logs
log = logs.get()
class Tuned(object):
def __init__(self, *args, **kwargs):
log.debug("something")
pass

1
tuned Symbolic link
View file

@ -0,0 +1 @@
src

90
tuned.py Executable file
View file

@ -0,0 +1,90 @@
#!/usr/bin/python
#
# tuned: A simple daemon that performs monitoring and adaptive configuration
# of devices in the system
#
# Copyright (C) 2008-2011 Red Hat, Inc.
#
# 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.
#
import tuned
import atexit
import getopt
import os
import signal
import sys
def usage():
print "Usage: tuned [-d|--daemon] [-c conffile|--config=conffile] [-D|--debug]"
def error(message):
print >>sys.stderr, message
def handle_signal(signum, callback):
def wrapper(_signum, _frame):
if signum == _signum:
callback()
signal.signal(signum, wrapper)
if __name__ == "__main__":
try:
opts, args = getopt.getopt(sys.argv[1:], "dc:D", ["daemon", "config=", "debug"])
except getopt.error as e:
error("Error parsing command-line arguments: %s" % e)
usage()
sys.exit(1)
if len(args) > 0:
error("Too many arguments.")
usage()
sys.exit(1)
config_file = None
daemon = False
debug = False
for (opt, val) in opts:
if opt in ['-d', "--daemon"]:
daemon = True
elif opt in ['-c', "--config"]:
config_file = val
elif opt in ['-D', "--debug"]:
debug = True
log = tuned.logs.get()
if (debug):
log.setLevel("DEBUG")
if os.getuid() != 0:
if daemon:
log.critical("Superuser permissions are needed.")
sys.exit(1)
else:
log.warn("Superuser permissions are needed. Most tunings will not work!")
tuned_daemon = tuned.Daemon(config_file, debug)
handle_signal(signal.SIGHUP, tuned_daemon.reload)
handle_signal(signal.SIGINT, tuned_daemon.terminate)
handle_signal(signal.SIGTERM, tuned_daemon.terminate)
if daemon:
log.switch_to_file()
tuned_daemon.daemonize()
atexit.register(tuned_daemon.cleanup)
tuned_daemon.run()