mirror of https://github.com/nocturn9x/nimd.git
Failed attempts to fix missing stderr from supervised processes
This commit is contained in:
parent
d6c46b3543
commit
b68b6f5e74
|
@ -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")
|
||||||
|
|
|
@ -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()}")
|
||||||
|
|
||||||
|
|
27
src/main.nim
27
src/main.nim
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue