mirror of
/repos/baseimage-docker.git
synced 2025-12-31 08:11:29 +01:00
When a container is stopped with 'docker stop', SIGTERM is sent to the init process. Unfortunately neither bash nor runit-init handle that correctly, so we write our own init system in Python that also waits for all services to shutdown.
65 lines
1.6 KiB
Python
Executable File
65 lines
1.6 KiB
Python
Executable File
#!/usr/bin/python2
|
|
import os, sys, signal, errno
|
|
|
|
def reap_child(signum, frame):
|
|
global pid, status, waiting_for_runit
|
|
try:
|
|
result = os.wait3(os.WNOHANG)
|
|
if result is not None and pid == result[0]:
|
|
status = result[1]
|
|
except OSError:
|
|
pass
|
|
|
|
def stop_runit(signum, frame):
|
|
global pid
|
|
print("*** Shutting down runit (PID %d)..." % pid)
|
|
try:
|
|
os.kill(pid, signal.SIGHUP)
|
|
except OSError:
|
|
pass
|
|
|
|
# Start runit.
|
|
signal.signal(signal.SIGCHLD, reap_child)
|
|
print("*** Booting runit...")
|
|
pid = os.spawnl(os.P_NOWAIT, "/usr/sbin/runsvdir-start", "/usr/sbin/runsvdir-start")
|
|
print("*** Runit started as PID %d" % pid)
|
|
signal.signal(signal.SIGTERM, stop_runit)
|
|
|
|
# Wait for runit, and while waiting, reap any adopted orphans.
|
|
done = False
|
|
while not done:
|
|
try:
|
|
this_pid, status = os.waitpid(pid, 0)
|
|
done = True
|
|
except OSError as e:
|
|
if e.errno == errno.EINTR:
|
|
# Try again
|
|
pass
|
|
else:
|
|
# The SIGCHLD handler probably caught it.
|
|
done = True
|
|
|
|
# Runit has exited. Reset signal handlers.
|
|
print("*** Runit exited with code %s. Waiting for all services to shut down..." % status)
|
|
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
|
|
signal.signal(signal.SIGTERM, signal.SIG_DFL)
|
|
signal.siginterrupt(signal.SIGCHLD, False)
|
|
signal.siginterrupt(signal.SIGTERM, False)
|
|
|
|
# Wait at most 5 seconds for services to shut down.
|
|
import time
|
|
|
|
def shutdown(signum = None, frame = None):
|
|
global status
|
|
if status is not None:
|
|
sys.exit(status)
|
|
|
|
signal.signal(signal.SIGALRM, shutdown)
|
|
signal.alarm(5)
|
|
done = False
|
|
while not done:
|
|
done = os.system("/usr/bin/sv status /etc/service/* | grep -q '^run:'") != 0
|
|
if not done:
|
|
time.sleep(0.5)
|
|
shutdown()
|