Merge branch 'ckuehl_build_and_tests_in_docker'

This commit is contained in:
Chris Kuehl 2015-08-05 11:20:17 -07:00
commit 0b09f86af6
14 changed files with 234 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
dumb-init
dist/
*.deb

10
Dockerfile Normal file
View file

@ -0,0 +1,10 @@
FROM debian:jessie
MAINTAINER Chris Kuehl <ckuehl@yelp.com>
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
apt-get install -y --no-install-recommends \
build-essential devscripts equivs && \
apt-get clean
WORKDIR /mnt
ENTRYPOINT mk-build-deps -i && make builddeb

44
Makefile Normal file
View file

@ -0,0 +1,44 @@
DOCKER_TEST := sh -c 'dpkg -i /mnt/dist/*.deb && cd /mnt/test && ./test'
.PHONY: build
build:
$(CC) -static -Wall -Werror -o dumb-init dumb-init.c
.PHONY: clean
clean:
rm -rf dumb-init dist/ *.deb
.PHONY: builddeb
builddeb:
debuild -us -uc -b
rm -rf dist && mkdir dist
mv ../dumb-init_*.deb dist/
.PHONY: builddeb-docker
builddeb-docker: docker-image
docker run -v $(PWD):/mnt dumb-init-build
.PHONY: docker-image
docker-image:
docker build -t dumb-init-build .
.PHONY: itest itest_lucid itest_precise itest_trusty itest_wheezy itest_jessie itest_stretch
itest: itest_lucid itest_precise itest_trusty itest_wheezy itest_jessie itest_stretch
itest_lucid: builddeb-docker
docker run -v $(PWD):/mnt:ro ubuntu:lucid $(DOCKER_TEST)
itest_precise: builddeb-docker
docker run -v $(PWD):/mnt:ro ubuntu:precise $(DOCKER_TEST)
itest_trusty: builddeb-docker
docker run -v $(PWD):/mnt:ro ubuntu:trusty $(DOCKER_TEST)
itest_wheezy: builddeb-docker
docker run -v $(PWD):/mnt:ro debian:wheezy $(DOCKER_TEST)
itest_jessie: builddeb-docker
docker run -v $(PWD):/mnt:ro debian:jessie $(DOCKER_TEST)
itest_stretch: builddeb-docker
docker run -v $(PWD):/mnt:ro debian:stretch $(DOCKER_TEST)

5
debian/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.log
*.substvars
files
substvars
dumb-init/

5
debian/changelog vendored Normal file
View file

@ -0,0 +1,5 @@
dumb-init (0.0.1) unstable; urgency=low
* Initial release.
-- Chris Kuehl <ckuehl@yelp.com> Wed, 29 Jul 2015 15:39:11 -0700

1
debian/compat vendored Normal file
View file

@ -0,0 +1 @@
7

26
debian/control vendored Normal file
View file

@ -0,0 +1,26 @@
Source: dumb-init
Section: utils
Priority: extra
Maintainer: Chris Kuehl <ckuehl@yelp.com>
Build-Depends: debhelper (>= 7), gcc, fakeroot
Standards-Version: 3.9.6
Package: dumb-init
Architecture: any
Depends: ${misc:Depends}
Description: Simple wrapper script which proxies signals to a child
Docker runs your processes as PID1. The kernel doesn't apply default signal
handling to PID1 processes, so if your process doesn't register a custom
signal handler, signals like TERM will just bounce off your process.
.
This can result in cases where sending signals to a `docker run` process
results in the run process exiting, but the container continuing in the
background.
.
A workaround is to wrap your script in this proxy, which runs as PID1. Your
process then runs as some other PID, and the kernel won't treat the signals
that are proxied to them specially.
.
The proxy dies when your process dies, so it must not double-fork or do other
weird things (this is basically a requirement for doing things sanely in
Docker anyway).

1
debian/install vendored Normal file
View file

@ -0,0 +1 @@
dumb-init /usr/bin/

3
debian/rules vendored Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/make -f
%:
dh $@

1
debian/source/format vendored Normal file
View file

@ -0,0 +1 @@
3.0 (native)

80
dumb-init.c Normal file
View file

@ -0,0 +1,80 @@
/*
* dumb-init is a simple wrapper program designed to run as PID 1 and pass
* signals to its children.
*
* Usage:
* ./dumb-init python -c 'while True: pass'
*
* To get debug output on stderr, run with DUMB_INIT_DEBUG=1.
*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t child = -1;
char debug = 0;
void signal_handler(int signum) {
if (debug)
fprintf(stderr, "Received signal %d.\n", signum);
if (child > 0) {
kill(child, signum);
if (debug)
fprintf(stderr, "Forwarded signal to child.\n");
}
}
int main(int argc, char *argv[]) {
int signum;
char* debug_env;
if (argc < 2) {
fprintf(stderr, "Try providing some arguments.\n");
return 1;
}
debug_env = getenv("DUMB_INIT_DEBUG");
if (debug_env && strcmp(debug_env, "1") == 0)
debug = 1;
/* register signal handlers */
for (signum = 1; signum < 32; signum++) {
if (signum == SIGKILL || signum == SIGSTOP || signum == SIGCHLD)
continue;
if (signal(signum, signal_handler) == SIG_ERR) {
fprintf(stderr, "Error: Couldn't register signal handler for signal `%d`. Exiting.\n", signum);
return 1;
}
}
/* launch our process */
child = fork();
if (child < 0) {
fprintf(stderr, "Unable to fork. Exiting.\n");
return 1;
}
if (child == 0) {
execvp(argv[1], &argv[1]);
} else {
if (debug)
fprintf(stderr, "Child spawned with PID %d.\n", child);
waitpid(child, NULL, 0);
if (debug)
fprintf(stderr, "Child exited, goodbye.\n");
}
return 0;
}

14
test/print-signals Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh -eu
# Print received signals into a file, one per line
file="$1"
. ./testlib.sh
for i in $(catchable_signals); do
trap "echo $i > \"$file\"" "$i"
done
echo 'ready' > "$file"
# loop forever
while :; do true; done

37
test/test Executable file
View file

@ -0,0 +1,37 @@
#!/bin/sh -eum
# Try sending all signals via dumb-init to our `print-signals` script, ensure
# they were all received.
. ./testlib.sh
# The easiest way to communicate with the background process is with a FIFO.
# (piping spawns additional subshells and makes it hard to get the right PID)
fifo=$(mktemp -u)
mkfifo -m 600 "$fifo"
dumb-init ./print-signals "$fifo" &
pid="$!"
# Wait for `print-signals` to indicate it's ready.
head -n1 "$fifo" > /dev/null
for expected in $(catchable_signals); do
kill -s "$expected" "$pid"
echo -n "Sent signal ${expected}... "
received=$(timeout 1 head -n1 "$fifo") || {
echo
echo "Error: Didn't receive signal within 1 second."
exit 1
}
echo "received signal ${received}."
if [ "$expected" -ne "$received" ]; then
echo "Error: Received signal $received, but expected signal $expected."
exit 1
fi
done
# Turn off job monitoring so we don't get a spurious "[1] + Killed" printed
set +m
kill -9 "$pid"
rm "$fifo"

4
test/testlib.sh Normal file
View file

@ -0,0 +1,4 @@
catchable_signals() {
# We can't handle the signals SIGKILL=9, SIGCHLD=17, SIGSTOP=19
seq 1 31 | grep -vE '^(9|17|19)$'
}