chore: Update proginit to 1.4.0
This commit is contained in:
@@ -5,19 +5,20 @@
|
||||
__author__ = "Sven Sager"
|
||||
__copyright__ = "Copyright (C) 2018-2023 Sven Sager"
|
||||
__license__ = "LGPL-2.0-or-later"
|
||||
__version__ = "1.3.2"
|
||||
__version__ = "1.4.0"
|
||||
|
||||
import logging
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from configparser import ConfigParser
|
||||
from enum import Enum
|
||||
from os import R_OK, W_OK, access, environ, getpid, remove
|
||||
from os.path import abspath, dirname, exists, join
|
||||
from shutil import copy, move
|
||||
from threading import Event
|
||||
|
||||
try:
|
||||
# Import program version from meta data module of your program
|
||||
# Import the program version from the meta-data module of your program
|
||||
from .__about__ import __version__ as external_version
|
||||
except Exception:
|
||||
external_version = None
|
||||
@@ -26,11 +27,12 @@ programname = "revpi-middleware" # Program name
|
||||
program_version = external_version or "a.b.c"
|
||||
|
||||
conf_rw = False # If you want so save the configuration with .save_conf() set to True
|
||||
conf_rw_save = False # Create new conf file in same directory and move to old one
|
||||
conf_rw_backup = False # Keep a backup of old conf file [filename].bak
|
||||
_extend_daemon_startup_timeout = 0.0 # Default startup timeout is 90 seconds
|
||||
conf_rw_save = False # Create a new conf file in the same directory and move to the old one
|
||||
conf_rw_backup = False # Keep a backup of an old conf file [filename].bak
|
||||
_extend_daemon_startup_timeout = 0.0 # The default startup timeout is 90 seconds
|
||||
|
||||
conf = ConfigParser()
|
||||
pargs = Namespace(daemon=False, verbose=0)
|
||||
logger = logging.getLogger()
|
||||
pidfile = "/var/run/{0}.pid".format(programname)
|
||||
_daemon_started_up = Event()
|
||||
@@ -90,11 +92,19 @@ def cleanup():
|
||||
sys.stdout.close()
|
||||
|
||||
|
||||
def reconfigure_logger():
|
||||
class StdLogOutput(Enum):
|
||||
"""Enum for the different output streams of the logger."""
|
||||
|
||||
NONE = ""
|
||||
STDOUT = "stdout"
|
||||
STDERR = "stderr"
|
||||
|
||||
|
||||
def reconfigure_logger(std_output: StdLogOutput = StdLogOutput.STDOUT):
|
||||
"""Configure logging module of program."""
|
||||
|
||||
class FilterDebug(logging.Filter):
|
||||
"""Set this filter to log handler if verbose level is > 1."""
|
||||
"""Set this filter to log handler if the verbose level is > 1."""
|
||||
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
remove_record = False
|
||||
@@ -104,27 +114,31 @@ def reconfigure_logger():
|
||||
|
||||
return not remove_record
|
||||
|
||||
# Clear all log handler
|
||||
# Clear all log handlers
|
||||
for lhandler in logger.handlers.copy():
|
||||
lhandler.close()
|
||||
logger.removeHandler(lhandler)
|
||||
|
||||
if pargs.daemon:
|
||||
# Create daemon log file
|
||||
# Create the daemon log file
|
||||
fh_logfile = open("/var/log/{0}.log".format(programname), "a")
|
||||
|
||||
# Close stdout and use logfile
|
||||
# Close stdout and use the logfile
|
||||
sys.stdout.close()
|
||||
sys.stdout = fh_logfile
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
# Create new log handler
|
||||
# Create the new log handler
|
||||
if pargs.verbose > 2:
|
||||
log_frm = "{asctime} [{levelname:8}] {name} {message}"
|
||||
else:
|
||||
log_frm = "{asctime} [{levelname:8}] {message}"
|
||||
logformat = logging.Formatter(log_frm, datefmt="%Y-%m-%d %H:%M:%S", style="{")
|
||||
lhandler = logging.StreamHandler(sys.stdout)
|
||||
|
||||
if std_output is not StdLogOutput.NONE:
|
||||
lhandler = logging.StreamHandler(
|
||||
sys.stdout if std_output is StdLogOutput.STDOUT else sys.stderr
|
||||
)
|
||||
lhandler.setFormatter(logformat)
|
||||
logger.addHandler(lhandler)
|
||||
|
||||
@@ -147,13 +161,13 @@ def reconfigure_logger():
|
||||
|
||||
def reload_conf(clear_load=False) -> None:
|
||||
"""
|
||||
Reload config file.
|
||||
Reload the config file.
|
||||
|
||||
After successful reload, call set_startup_complete() function to inform
|
||||
After successful reload, call the set_startup_complete() function to inform
|
||||
systemd that all functions are available again.
|
||||
|
||||
If keys are commented out in conf file, they will still be in the conf file.
|
||||
To remove not existing keys set clear_load to True.
|
||||
If keys are commented out in the conf file, they will still be in the conf file.
|
||||
To remove not existing keys, set clear_load to True.
|
||||
|
||||
:param clear_load: Clear conf before reload
|
||||
"""
|
||||
@@ -161,11 +175,11 @@ def reload_conf(clear_load=False) -> None:
|
||||
# Inform systemd about reloading configuration
|
||||
_systemd_socket.sendto(b"RELOADING=1\n", _systemd_notify)
|
||||
|
||||
# Reset started up event for the set_startup_complete function
|
||||
# Reset started-up event for the set_startup_complete function
|
||||
_daemon_started_up.clear()
|
||||
|
||||
if "conffile" in pargs:
|
||||
# Check config file
|
||||
# Check the config file
|
||||
if not access(pargs.conffile, R_OK):
|
||||
raise RuntimeError("can not access config file '{0}'".format(pargs.conffile))
|
||||
if conf_rw:
|
||||
@@ -212,7 +226,7 @@ def startup_complete():
|
||||
this daemon are available so that the starts of further daemons can be
|
||||
properly timed.
|
||||
|
||||
The systemd unit file that is supposed to start this demon must be set
|
||||
The systemd unit file supposed to start this demon must be set
|
||||
to 'Type=notify'. If the daemon supports reloading the settings,
|
||||
'ExecReload=/bin/kill -HUP $MAINPID' must also be set. The daemon must
|
||||
call this function again after the reload in order to signal systemd the
|
||||
@@ -231,13 +245,13 @@ def startup_complete():
|
||||
return
|
||||
|
||||
if _systemd_notify:
|
||||
# Inform systemd about complete startup of daemon process
|
||||
# Inform systemd about the complete startup of the daemon process
|
||||
_systemd_socket.sendto(b"READY=1\n", _systemd_notify)
|
||||
|
||||
if pargs.daemon:
|
||||
from os import kill
|
||||
|
||||
# Send SIGTERM signal to main process
|
||||
# Send SIGTERM signal to the main process
|
||||
kill(_daemon_main_pid, 15)
|
||||
|
||||
_daemon_started_up.set()
|
||||
@@ -246,35 +260,15 @@ def startup_complete():
|
||||
# Generate command arguments of the program
|
||||
parser = ArgumentParser(
|
||||
prog=programname,
|
||||
# todo: Add program description for help
|
||||
description="Program description",
|
||||
)
|
||||
parser.add_argument("--version", action="version", version=f"%(prog)s {program_version}")
|
||||
if can_be_forked():
|
||||
# Show the parameter only on systems that support fork call
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--daemon",
|
||||
action="store_true",
|
||||
dest="daemon",
|
||||
help="run program as a daemon in background",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--conffile",
|
||||
dest="conffile",
|
||||
default="/etc/{0}/{0}.conf".format(programname),
|
||||
help="application configuration file",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--logfile",
|
||||
dest="logfile",
|
||||
help="save log entries to this file",
|
||||
)
|
||||
|
||||
# TODO: Insert more arguments
|
||||
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
@@ -292,6 +286,10 @@ if exists(open_source_licenses):
|
||||
dest="oss_licenses",
|
||||
help="print packed open-source-licenses and exit",
|
||||
)
|
||||
|
||||
|
||||
def init_app(logger_std_output: StdLogOutput = StdLogOutput.STDOUT):
|
||||
global pargs
|
||||
pargs = parser.parse_args()
|
||||
|
||||
# Process open-source-licenses argument, if set (only affects bundled apps)
|
||||
@@ -308,7 +306,7 @@ if "verbose" not in pargs:
|
||||
|
||||
# Check if the program should run as a daemon
|
||||
if pargs.daemon:
|
||||
# Check if daemon is already running
|
||||
# Check if the daemon is already running
|
||||
if exists(pidfile):
|
||||
logger.error("Program already running as daemon. Check '{0}'".format(pidfile))
|
||||
sys.exit(1)
|
||||
@@ -318,7 +316,7 @@ if pargs.daemon:
|
||||
|
||||
pid = fork()
|
||||
if pid > 0:
|
||||
# Main process waits for exit till startup is complete
|
||||
# The main process waits for exit till startup is complete
|
||||
from os import kill
|
||||
from signal import SIGKILL, SIGTERM, signal
|
||||
|
||||
@@ -333,20 +331,19 @@ if pargs.daemon:
|
||||
kill(pid, SIGKILL)
|
||||
sys.exit(1)
|
||||
|
||||
# Main process writes pidfile with pid of forked process
|
||||
# Main process writes pidfile with pid of the forked process
|
||||
with open(pidfile, "w") as f:
|
||||
f.write(str(pid))
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# Get absolute paths
|
||||
pwd = abspath(".")
|
||||
|
||||
# Configure logger
|
||||
if "logfile" in pargs and pargs.logfile is not None and dirname(pargs.logfile) == "":
|
||||
pargs.logfile = join(pwd, pargs.logfile)
|
||||
reconfigure_logger()
|
||||
reconfigure_logger(logger_std_output)
|
||||
|
||||
# Initialize configparser of globalconfig
|
||||
if "conffile" in pargs and dirname(pargs.conffile) == "":
|
||||
@@ -357,3 +354,7 @@ if "conffile" in pargs and dirname(pargs.conffile) == "":
|
||||
|
||||
# Log PID for development purposes
|
||||
logger.debug("Running with PID {}".format(getpid()))
|
||||
|
||||
|
||||
# Initialize global config
|
||||
# init_app()
|
||||
|
||||
Reference in New Issue
Block a user