summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpendulm <lonependulm@gmail.com>2021-04-02 19:33:05 +0800
committerMatthew Heon <mheon@redhat.com>2021-04-16 13:46:54 -0400
commitc8130be174e0f5209661ab454bee37a3765d1b04 (patch)
treec13e5c794b939614bed6d9ebfa55bd843c88cc60
parentc042b4c82014c7a3841969c3bfab70203e7cecd6 (diff)
downloadpodman-c8130be174e0f5209661ab454bee37a3765d1b04.tar.gz
podman-c8130be174e0f5209661ab454bee37a3765d1b04.tar.bz2
podman-c8130be174e0f5209661ab454bee37a3765d1b04.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.c58
-rw-r--r--test/system/270-socket-activation.bats103
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