diff options
author | pendulm <lonependulm@gmail.com> | 2021-04-02 19:33:05 +0800 |
---|---|---|
committer | pendulm <lonependulm@gmail.com> | 2021-04-05 17:43:11 +0800 |
commit | 11917a1a6b74a9abf18ae5ed307007bf9f316a8f (patch) | |
tree | 7e77e3f8899ac43b2a7b02cac8f372c7ff32aade | |
parent | 23ee8b1df1f70aaad4fc4bc9c0c6b17f7aae5c8a (diff) | |
download | podman-11917a1a6b74a9abf18ae5ed307007bf9f316a8f.tar.gz podman-11917a1a6b74a9abf18ae5ed307007bf9f316a8f.tar.bz2 podman-11917a1a6b74a9abf18ae5ed307007bf9f316a8f.zip |
Move socket activation check into init() and set global condition.
So rootless setup could use this condition in parent and child, child
podman should adjust LISTEN_PID to its self PID.
Add system test for systemd socket activation
Signed-off-by: pendulm <lonependulm@gmail.com>
-rw-r--r-- | pkg/rootless/rootless_linux.c | 58 | ||||
-rw-r--r-- | test/system/270-socket-activation.bats | 103 |
2 files changed, 149 insertions, 12 deletions
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 7a2bf0377..918b9a7e6 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -61,6 +61,10 @@ static int open_files_max_fd; static fd_set *open_files_set; static uid_t rootless_uid_init; static gid_t rootless_gid_init; +static bool do_socket_activation = false; +static char *saved_systemd_listen_fds; +static char *saved_systemd_listen_pid; +static char *saved_systemd_listen_fdnames; static int syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid) @@ -242,6 +246,10 @@ static void __attribute__((constructor)) init() { const char *xdg_runtime_dir; const char *pause; + const char *listen_pid; + const char *listen_fds; + const char *listen_fdnames; + DIR *d; pause = getenv ("_PODMAN_PAUSE"); @@ -293,6 +301,26 @@ static void __attribute__((constructor)) init() closedir (d); } + listen_pid = getenv("LISTEN_PID"); + listen_fds = getenv("LISTEN_FDS"); + listen_fdnames = getenv("LISTEN_FDNAMES"); + + if (listen_pid != NULL && listen_fds != NULL && strtol(listen_pid, NULL, 10) == getpid()) + { + // save systemd socket environment for rootless child + do_socket_activation = true; + saved_systemd_listen_pid = strdup(listen_pid); + saved_systemd_listen_fds = strdup(listen_fds); + saved_systemd_listen_fdnames = strdup(listen_fdnames); + if (saved_systemd_listen_pid == NULL + || saved_systemd_listen_fds == NULL + || saved_systemd_listen_fdnames == NULL) + { + fprintf (stderr, "save socket listen environments error: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + } + /* Shortcut. If we are able to join the pause pid file, do it now so we don't need to re-exec. */ xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); @@ -635,6 +663,12 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) for (f = 3; f <= open_files_max_fd; f++) if (is_fd_inherited (f)) close (f); + if (do_socket_activation) + { + unsetenv ("LISTEN_PID"); + unsetenv ("LISTEN_FDS"); + unsetenv ("LISTEN_FDNAMES"); + } return pid; } @@ -660,6 +694,15 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path) _exit (EXIT_FAILURE); } + if (do_socket_activation) + { + char s[32]; + sprintf (s, "%d", getpid()); + setenv ("LISTEN_PID", s, true); + setenv ("LISTEN_FDS", saved_systemd_listen_fds, true); + setenv ("LISTEN_FDNAMES", saved_systemd_listen_fdnames, true); + } + setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1); setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1); setenv ("_CONTAINERS_ROOTLESS_GID", gid, 1); @@ -777,9 +820,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re char **argv; char uid[16]; char gid[16]; - char *listen_fds = NULL; - char *listen_pid = NULL; - bool do_socket_activation = false; char *cwd = getcwd (NULL, 0); sigset_t sigset, oldsigset; @@ -789,14 +829,6 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re _exit (EXIT_FAILURE); } - listen_pid = getenv("LISTEN_PID"); - listen_fds = getenv("LISTEN_FDS"); - - if (listen_pid != NULL && listen_fds != NULL) - { - if (strtol(listen_pid, NULL, 10) == getpid()) - do_socket_activation = true; - } sprintf (uid, "%d", geteuid ()); sprintf (gid, "%d", getegid ()); @@ -814,7 +846,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re { long num_fds; - num_fds = strtol (listen_fds, NULL, 10); + num_fds = strtol (saved_systemd_listen_fds, NULL, 10); if (num_fds != LONG_MIN && num_fds != LONG_MAX) { int f; @@ -863,6 +895,8 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re char s[32]; sprintf (s, "%d", getpid()); setenv ("LISTEN_PID", s, true); + setenv ("LISTEN_FDS", saved_systemd_listen_fds, true); + setenv ("LISTEN_FDNAMES", saved_systemd_listen_fdnames, true); } setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1); diff --git a/test/system/270-socket-activation.bats b/test/system/270-socket-activation.bats new file mode 100644 index 000000000..25206c6a7 --- /dev/null +++ b/test/system/270-socket-activation.bats @@ -0,0 +1,103 @@ +#!/usr/bin/env bats -*- bats -*- +# +# Tests podman system service under systemd socket activation +# + +load helpers + +SERVICE_NAME="podman_test_$(random_string)" + +SYSTEMCTL="systemctl" +UNIT_DIR="/usr/lib/systemd/system" +SERVICE_SOCK_ADDR="/run/podman/podman.sock" + +if is_rootless; then + UNIT_DIR="$HOME/.config/systemd/user" + mkdir -p $UNIT_DIR + + SYSTEMCTL="$SYSTEMCTL --user" + if [ -z "$XDG_RUNTIME_DIR" ]; then + export XDG_RUNTIME_DIR=/run/user/$(id -u) + fi + SERVICE_SOCK_ADDR="$XDG_RUNTIME_DIR/podman/podman.sock" +fi + +SERVICE_FILE="$UNIT_DIR/$SERVICE_NAME.service" +SOCKET_FILE="$UNIT_DIR/$SERVICE_NAME.socket" + + +function setup() { + skip_if_remote "systemd tests are meaningless over remote" + + basic_setup + + cat > $SERVICE_FILE <<EOF +[Unit] +Description=Podman API Service +Requires=podman.socket +After=podman.socket +Documentation=man:podman-system-service(1) +StartLimitIntervalSec=0 + +[Service] +Type=exec +KillMode=process +Environment=LOGGING="--log-level=info" +ExecStart=$PODMAN $LOGGING system service -t 2 +EOF + cat > $SOCKET_FILE <<EOF +[Unit] +Description=Podman API Socket +Documentation=man:podman-system-service(1) + +[Socket] +ListenStream=%t/podman/podman.sock +SocketMode=0660 + +[Install] +WantedBy=sockets.target +EOF + + # ensure pause die before each test runs + if is_rootless; then + local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid" + if [ -f $pause_pid ]; then + kill -9 $(cat $pause_pid) 2> /dev/null + rm -f $pause_pid + fi + fi + $SYSTEMCTL start "$SERVICE_NAME.socket" +} + +function teardown() { + $SYSTEMCTL stop "$SERVICE_NAME.socket" + rm -f "$SERVICE_FILE" "$SOCKET_FILE" + $SYSTEMCTL daemon-reload + basic_teardown +} + +@test "podman system service - socket activation - no container" { + run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping + is "$output" "OK" "podman service responses normally" +} + +@test "podman system service - socket activation - exist container " { + run_podman run $IMAGE sleep 90 + run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping + is "$output" "OK" "podman service responses normally" +} + +@test "podman system service - socket activation - kill rootless pause " { + if ! is_rootless; then + skip "root podman no need pause process" + fi + run_podman run $IMAGE sleep 90 + local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid" + if [ -f $pause_pid ]; then + kill -9 $(cat $pause_pid) 2> /dev/null + fi + run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping + is "$output" "OK" "podman service responses normally" +} + +# vim: filetype=sh |