Failed attempts to fix missing stderr from supervised processes

This commit is contained in:
nocturn9x 2021-12-27 15:08:57 +01:00
parent d6c46b3543
commit b68b6f5e74
3 changed files with 72 additions and 79 deletions

View File

@ -23,10 +23,10 @@ import shutdown
proc mainLoop*(logger: Logger) = proc mainLoop*(logger: Logger, workers: int = 1) =
## NimD's main execution loop ## NimD's main execution loop
logger.info("Processing default runlevel") logger.info("Processing default runlevel")
startServices(logger, workers=1, level=Default) startServices(logger, workers=workers, level=Default)
logger.debug(&"Unblocking signals") logger.debug(&"Unblocking signals")
unblockSignals(logger) unblockSignals(logger)
logger.info("System initialization complete, idling on control socket") logger.info("System initialization complete, idling on control socket")

View File

@ -219,14 +219,13 @@ proc removeService*(service: Service) =
break break
proc loggerWorker(logger: Logger, service: Service, process: Process) = proc streamLoggerWorker(logger: Logger, service: Service, stream: Stream) =
## Captures the output of a given process and relays it ## Captures the output of a given process and relays it
## in a formatted manner into our logging system ## in a formatted manner into our logging system
try: try:
logger.debug("Switching logs to file") logger.debug("Switching logs to file")
logger.switchToFile() # logger.switchToFile()
var line: string = "" var line: string = ""
var stream = process.outputStream
while stream.readLine(line): while stream.readLine(line):
logger.info(&"{service.name}: {line}") logger.info(&"{service.name}: {line}")
except: except:
@ -244,63 +243,62 @@ proc supervisorWorker(logger: Logger, service: Service, process: Process) =
logger.error(&"Error, cannot fork: {posix.strerror(posix.errno)}") logger.error(&"Error, cannot fork: {posix.strerror(posix.errno)}")
elif p == 0: elif p == 0:
logger.trace(&"New child has been spawned") logger.trace(&"New child has been spawned")
loggerWorker(logger, service, process) streamLoggerWorker(logger, service, process.outputStream)
else: var pid = process.processID
var pid = process.processID var status: cint
var status: cint var returnCode: int
var returnCode: int var sig: int
var sig: int var process: Process
var process: Process logger.debug("Switching logs to file")
logger.debug("Switching logs to file") logger.switchToFile()
logger.switchToFile() while true:
while true: logger.trace(&"Calling waitpid() on {pid}")
logger.trace(&"Calling waitpid() on {pid}") returnCode = posix.waitPid(cint(pid), status, WUNTRACED)
returnCode = posix.waitPid(cint(pid), status, WUNTRACED) if WIFEXITED(status):
if WIFEXITED(status): sig = 0
sig = 0 elif WIFSIGNALED(status):
elif WIFSIGNALED(status): sig = WTERMSIG(status)
sig = WTERMSIG(status) else:
else: sig = -1
sig = -1 logger.trace(&"Call to waitpid() set status to {status} and returned {returnCode}, setting sig to {sig}")
logger.trace(&"Call to waitpid() set status to {status} and returned {returnCode}, setting sig to {sig}") case service.restart:
case service.restart: of Never:
of Never: logger.info(&"Service '{service.name}' ({returnCode}) has exited, shutting down controlling process")
logger.info(&"Service '{service.name}' ({returnCode}) has exited, shutting down controlling process") break
of Always:
if sig > 0:
logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it")
elif sig == 0:
logger.info(&"Service '{service.name}' has exited gracefully, sleeping {service.restartDelay} seconds before restarting it")
else:
logger.info(&"Service '{service.name}' has exited, sleeping {service.restartDelay} seconds before restarting it")
removeManagedProcess(pid)
sleep(service.restartDelay * 1000)
var split = shlex(service.exec)
if split.error:
logger.error(&"Error while restarting service '{service.name}': invalid exec syntax")
break break
of Always: var arguments = split.words
if sig > 0: let progName = arguments[0]
logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it") arguments = arguments[1..^1]
elif sig == 0: process = startProcess(progName, workingDir=service.workDir, args=arguments)
logger.info(&"Service '{service.name}' has exited gracefully, sleeping {service.restartDelay} seconds before restarting it") pid = process.processID()
else: of OnFailure:
logger.info(&"Service '{service.name}' has exited, sleeping {service.restartDelay} seconds before restarting it") if sig > 0:
removeManagedProcess(pid) logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it")
sleep(service.restartDelay * 1000) removeManagedProcess(pid)
var split = shlex(service.exec) sleep(service.restartDelay * 1000)
if split.error: var split = shlex(service.exec)
logger.error(&"Error while restarting service '{service.name}': invalid exec syntax") if split.error:
break logger.error(&"Error while restarting service '{service.name}': invalid exec syntax")
var arguments = split.words break
let progName = arguments[0] var arguments = split.words
arguments = arguments[1..^1] let progName = arguments[0]
process = startProcess(progName, workingDir=service.workDir, args=arguments) arguments = arguments[1..^1]
pid = process.processID() process = startProcess(progName, workingDir=service.workDir, args=arguments)
of OnFailure: pid = process.processID()
if sig > 0: if process != nil:
logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it") process.close()
removeManagedProcess(pid)
sleep(service.restartDelay * 1000)
var split = shlex(service.exec)
if split.error:
logger.error(&"Error while restarting service '{service.name}': invalid exec syntax")
break
var arguments = split.words
let progName = arguments[0]
arguments = arguments[1..^1]
process = startProcess(progName, workingDir=service.workDir, args=arguments)
pid = process.processID()
if process != nil:
process.close()
proc startService(logger: Logger, service: Service) = proc startService(logger: Logger, service: Service) =
@ -319,7 +317,7 @@ proc startService(logger: Logger, service: Service) =
var arguments = split.words var arguments = split.words
let progName = arguments[0] let progName = arguments[0]
arguments = arguments[1..^1] arguments = arguments[1..^1]
process = startProcess(progName, workingDir=service.workDir, args=arguments, options=if service.useParentStreams: {poParentStreams} else: {poUsePath, poDaemon, poStdErrToStdOut}) process = startProcess(progName, workingDir=service.workDir, args=arguments, options=if service.useParentStreams: {poParentStreams, poStdErrToStdOut} else: {poUsePath, poDaemon, poStdErrToStdOut})
if service.supervised or service.kind != Oneshot: if service.supervised or service.kind != Oneshot:
var pid = posix.fork() var pid = posix.fork()
if pid == -1: if pid == -1:
@ -329,7 +327,7 @@ proc startService(logger: Logger, service: Service) =
supervisorWorker(logger, service, process) supervisorWorker(logger, service, process)
# If the service is unsupervised we just spawn the logger worker (assuming it doesn't use poParentStreams) # If the service is unsupervised we just spawn the logger worker (assuming it doesn't use poParentStreams)
if not service.useParentStreams: if not service.useParentStreams:
loggerWorker(logger, service, process) streamLoggerWorker(logger, service, process.outputStream)
except: except:
logger.error(&"Error while starting service '{service.name}': {getCurrentExceptionMsg()}") logger.error(&"Error while starting service '{service.name}': {getCurrentExceptionMsg()}")

View File

@ -44,30 +44,25 @@ proc addStuff =
addShutdownHandler(newShutdownHandler(unmountAllDisks)) addShutdownHandler(newShutdownHandler(unmountAllDisks))
# Adds test services # Adds test services
var echoer = newService(name="echoer", description="prints owo", exec="/bin/echo owoooooooooo", var echoer = newService(name="echoer", description="prints owo", exec="/bin/echo owoooooooooo",
runlevel=Boot, kind=Oneshot, workDir=getCurrentDir(), runlevel=Boot, kind=Simple, workDir=getCurrentDir(),
supervised=false, restart=Never, restartDelay=0, supervised=false, restart=Always, restartDelay=5,
depends=(@[]), provides=(@[])) depends=(@[]), provides=(@[]))
var errorer = newService(name="errorer", description="la mamma di gavd", var errorer = newService(name="errorer", description="la mamma di gavd",
exec="/bin/false", supervised=true, restart=OnFailure, exec="/bin/false", supervised=true, restart=OnFailure,
restartDelay=5, runlevel=Boot, workDir="/", kind=Simple, restartDelay=5, runlevel=Boot, workDir="/", kind=Simple,
depends=(@[newDependency(Other, echoer)]), provides=(@[])) depends=(@[]), provides=(@[]))
var test = newService(name="broken", description="", exec="/bin/echo owo",
runlevel=Boot, kind=Oneshot, workDir=getCurrentDir(),
supervised=false, restart=Never, restartDelay=0,
depends=(@[newDependency(Other, echoer)]), provides=(@[]))
var exiter = newService(name="exiter", description="la mamma di licenziat", var exiter = newService(name="exiter", description="la mamma di licenziat",
exec="/bin/true", supervised=true, restart=Always, exec="/bin/true", supervised=true, restart=Always,
restartDelay=5, runlevel=Boot, workDir="/", kind=Simple, restartDelay=5, runlevel=Boot, workDir="/", kind=Simple,
depends=(@[newDependency(Other, errorer)]), provides=(@[])) depends=(@[newDependency(Other, errorer)]), provides=(@[]))
var shell = newService(name="login", description="A simple login shell", kind=Simple, var shell = newService(name="login", description="A simple login shell", kind=Simple,
getCurrentDir(), runlevel=Boot, exec="/bin/login -f root", getCurrentDir(), runlevel=Default, exec="/bin/login -f root",
supervised=true, restart=Always, restartDelay=0, depends=(@[]), provides=(@[]), supervised=true, restart=Always, restartDelay=5, depends=(@[]), provides=(@[]),
useParentStreams=true useParentStreams=true
) )
addService(errorer) addService(errorer)
addService(echoer) addService(echoer)
addService(exiter) addService(exiter)
addService(test)
addService(shell) addService(shell)
@ -126,7 +121,7 @@ proc main(logger: Logger, mountDisks: bool = true, fstab: string = "/etc/fstab",
logger.info("Processing boot runlevel") logger.info("Processing boot runlevel")
startServices(logger, workers=workerCount, level=Boot) startServices(logger, workers=workerCount, level=Boot)
logger.debug("Starting main loop") logger.debug("Starting main loop")
mainLoop(logger) mainLoop(logger, workers=workerCount)
when isMainModule: when isMainModule: