1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
# type: ignore
# pylint: disable=protected-access
import atexit
import os
import signal
from typing import Any, Optional
from supervisor.compat import as_string
from supervisor.events import ProcessStateFatalEvent, ProcessStateRunningEvent, ProcessStateStartingEvent, subscribe
from supervisor.options import ServerOptions
from supervisor.process import Subprocess
from supervisor.states import SupervisorStates
from supervisor.supervisord import Supervisor
from knot_resolver.utils.systemd_notify import systemd_notify
superd: Optional[Supervisor] = None
def check_for_fatal_manager(event: ProcessStateFatalEvent) -> None:
assert superd is not None
proc: Subprocess = event.process
processname = as_string(proc.config.name)
if processname == "manager":
# stop the whole supervisord gracefully
superd.options.logger.critical("manager process entered FATAL state! Shutting down")
superd.options.mood = SupervisorStates.SHUTDOWN
# force the interpreter to exit with exit code 1
atexit.register(lambda: os._exit(1))
def check_for_starting_manager(event: ProcessStateStartingEvent) -> None:
assert superd is not None
proc: Subprocess = event.process
processname = as_string(proc.config.name)
if processname == "manager":
# manager has sucessfully started, report it upstream
systemd_notify(STATUS="Starting services...")
def check_for_runnning_manager(event: ProcessStateRunningEvent) -> None:
assert superd is not None
proc: Subprocess = event.process
processname = as_string(proc.config.name)
if processname == "manager":
# manager has sucessfully started, report it upstream
systemd_notify(READY="1", STATUS="Ready")
def get_server_options_signal(self):
sig = self.signal_receiver.get_signal()
if sig == signal.SIGHUP and superd is not None:
superd.options.logger.info("received SIGHUP, forwarding to the process 'manager'")
manager_pid = superd.process_groups["manager"].processes["manager"].pid
os.kill(manager_pid, signal.SIGHUP)
return None
return sig
def inject(supervisord: Supervisor, **_config: Any) -> Any: # pylint: disable=useless-return
global superd
superd = supervisord
# This status notification here unsets the env variable $NOTIFY_SOCKET provided by systemd
# and stores it locally. Therefore, it shouldn't clash with $NOTIFY_SOCKET we are providing
# downstream
systemd_notify(STATUS="Initializing supervisord...")
# register events
subscribe(ProcessStateFatalEvent, check_for_fatal_manager)
subscribe(ProcessStateStartingEvent, check_for_starting_manager)
subscribe(ProcessStateRunningEvent, check_for_runnning_manager)
# forward SIGHUP to manager
ServerOptions.get_signal = get_server_options_signal
# this method is called by supervisord when loading the plugin,
# it should return XML-RPC object, which we don't care about
# That's why why are returning just None
return None
|