Lot of refactoring in the daemon class and some more cleanups.
This commit is contained in:
parent
ec3a61e019
commit
d815508396
4 changed files with 63 additions and 43 deletions
77
daemon.py
77
daemon.py
|
|
@ -1,30 +1,36 @@
|
|||
"""
|
||||
Generic linux daemon base class for python 3.x.
|
||||
# Copyright (c) 2022 Johannes Findeisen <you@hanez.org>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is furnished
|
||||
# to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice (including the next
|
||||
# paragraph) shall be included in all copies or substantial portions of the
|
||||
# Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Original Source:
|
||||
https://web.archive.org/web/20131017130434/http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
|
||||
https://web.archive.org/web/20131017130434/http://www.jejik.com/files/examples/daemon3x.py
|
||||
See files/daemon3x.py in the uplink source tree.
|
||||
|
||||
More Information:
|
||||
https://franklingu.github.io/programming/2016/03/01/creating-daemon-process-python-example-explanation/
|
||||
https://dpbl.wordpress.com/2017/02/12/a-tutorial-on-python-daemon/
|
||||
"""
|
||||
import atexit
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
from logging import getLogger
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import atexit
|
||||
import signal
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class Daemon:
|
||||
"""
|
||||
A generic daemon class.
|
||||
|
||||
Usage: subclass the daemon class and override the run() method.
|
||||
"""
|
||||
|
||||
|
|
@ -33,34 +39,35 @@ class Daemon:
|
|||
|
||||
def daemonize(self):
|
||||
"""
|
||||
Daemonize class. UNIX double fork mechanism.
|
||||
Daemonize the class using the UNIX double fork mechanism.
|
||||
"""
|
||||
|
||||
# Do first fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
# Exit first parent
|
||||
sys.exit(0)
|
||||
except OSError as err:
|
||||
logger.error('fork #1 failed: {0}\n'.format(err))
|
||||
logger.error(str("fork #1 failed: {0}".format(err)))
|
||||
sys.exit(1)
|
||||
|
||||
# decouple from parent environment
|
||||
# Decouple from parent environment
|
||||
os.chdir('/')
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
# Do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
# Exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError as err:
|
||||
logger.error('fork #2 failed: {0}\n'.format(err))
|
||||
logger.error(str("fork #2 failed: {0}".format(err)))
|
||||
sys.exit(1)
|
||||
|
||||
# redirect standard file descriptors
|
||||
# Redirect standard file descriptors
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = open(os.devnull, 'r')
|
||||
|
|
@ -71,7 +78,7 @@ class Daemon:
|
|||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# write pidfile
|
||||
# Write pidfile
|
||||
atexit.register(self.del_pid)
|
||||
|
||||
pid = str(os.getpid())
|
||||
|
|
@ -94,8 +101,8 @@ class Daemon:
|
|||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pid_file {0} already exist. Daemon already running?"
|
||||
logger.error(message.format(self.pid_file))
|
||||
message = "pid_file {0} already exist. daemon already running?"
|
||||
logger.error(str(message.format(self.pid_file)))
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
|
|
@ -107,7 +114,7 @@ class Daemon:
|
|||
Stop the daemon.
|
||||
"""
|
||||
|
||||
# Get the pid from the pidfile
|
||||
# Get the pid from the pid_file
|
||||
try:
|
||||
with open(self.pid_file, 'r') as pf:
|
||||
pid = int(pf.read().strip())
|
||||
|
|
@ -115,10 +122,9 @@ class Daemon:
|
|||
pid = None
|
||||
|
||||
if not pid:
|
||||
message = "pid_file {0} does not exist. Daemon not running?"
|
||||
logger.error(message.format(self.pid_file))
|
||||
# not an error in a restart
|
||||
return
|
||||
message = "pid_file {0} does not exist. daemon not running?"
|
||||
logger.error(str(message.format(self.pid_file)))
|
||||
return # not an error in a restart
|
||||
|
||||
# Try killing the daemon process
|
||||
try:
|
||||
|
|
@ -143,7 +149,8 @@ class Daemon:
|
|||
|
||||
def run(self):
|
||||
"""
|
||||
Override this method when you subclass Daemon.
|
||||
You should override this method when you subclass Daemon.
|
||||
|
||||
It will be called after the process has been daemonized by
|
||||
start() or restart().
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,4 +1,15 @@
|
|||
"""Generic linux daemon base class for python 3.x."""
|
||||
"""
|
||||
Generic linux daemon base class for python 3.x.
|
||||
|
||||
Original Source:
|
||||
https://web.archive.org/web/20131017130434/http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
|
||||
https://web.archive.org/web/20131017130434/http://www.jejik.com/files/examples/daemon3x.py
|
||||
See files/daemon3x.py in the uplink source tree.
|
||||
|
||||
More Information:
|
||||
https://franklingu.github.io/programming/2016/03/01/creating-daemon-process-python-example-explanation/
|
||||
https://dpbl.wordpress.com/2017/02/12/a-tutorial-on-python-daemon/
|
||||
"""
|
||||
|
||||
import sys, os, time, atexit, signal
|
||||
|
||||
|
|
|
|||
12
uplink
12
uplink
|
|
@ -31,13 +31,17 @@ import time
|
|||
from uplink import Uplink
|
||||
|
||||
# Version format: MAJOR.FEATURE.FIXES
|
||||
__version__ = "0.6.0"
|
||||
__version__ = "0.6.1"
|
||||
|
||||
# TODO: CHECK ALL ERROR HANDLING!!!
|
||||
# TODO: IDEA: Implement a small webserver inline to get statistics and graphs over the network?
|
||||
# Or maybe better as a separate daemon
|
||||
# Or maybe better as a separate daemon?
|
||||
# TODO: Make use of more args passed to the script
|
||||
# TODO: Implement a speedtest that will also run regularly but in an individual interval
|
||||
# TODO: become more verbose in each log level and log only to error when it really is an error
|
||||
# else log to info
|
||||
# TODO: Maybe make path to pid_file an arg to use /var/run/$user/uplink.pid instead of
|
||||
# /tmp/uplink.pid
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -139,7 +143,7 @@ def main():
|
|||
config_data = configfile.read()
|
||||
config = json.loads(config_data)
|
||||
except Exception as err:
|
||||
logger.error(str("uplink: configuration error!\n" + str(err)))
|
||||
logger.error(str("uplink: configuration error! {0}".format(err)))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
|
|
@ -175,7 +179,7 @@ def main():
|
|||
t.start()
|
||||
try:
|
||||
time.sleep(config["interval"])
|
||||
except KeyboardInterrupt as err:
|
||||
except KeyboardInterrupt:
|
||||
logger.info(str("uplink: program terminated by user!"))
|
||||
sys.exit(0)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ from fritzconnection.lib.fritzstatus import FritzStatus
|
|||
from logging import getLogger
|
||||
from threading import Thread
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -38,7 +37,6 @@ class Uplink(Daemon):
|
|||
|
||||
def __init__(self, pid_file, config):
|
||||
super().__init__(pid_file)
|
||||
self.pid_file = pid_file
|
||||
self.config = config
|
||||
self.date = None
|
||||
self.time = None
|
||||
|
|
@ -53,7 +51,7 @@ class Uplink(Daemon):
|
|||
password=config["database_password"],
|
||||
database=config["database"])
|
||||
except Exception as err:
|
||||
logger.error(str("uplink: Database connection failed: " + str(err)))
|
||||
logger.error(str("uplink: Database connection failed: {0}".format(err)))
|
||||
sys.exit(1)
|
||||
|
||||
timestamp = calendar.timegm(time.gmtime())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue