use journal namespace
This commit is contained in:
1 parent
ae4299a570
commit
4f0886b6cd
11 files changed
+201
-21
No files matched your search
+105
-5
@@ -31,6 +31,7 @@ DIST_DIR="${TERRARIA_DIST:-/var/lib/terraria/dist}"
|
||||
RUN_DIR="/run/terraria"
|
||||
SVC_USER="${TERRARIA_USER:-terraria}"
|
||||
STOP_TIMEOUT="${TERRARIA_STOP_TIMEOUT:-80}" # keep below TimeoutStopSec
|
||||
JOURNAL_NS=terraria # LogNamespace= in terraria@.service
|
||||
TERRACTL_VERSION="@VERSION@" # filled in by 'make install' / 'make deb'
|
||||
|
||||
die() { echo "terractl: $*" >&2; exit 1; }
|
||||
@@ -59,6 +60,7 @@ Admin commands:
|
||||
(worlds/configs archived to $BASE_DIR/.deleted/)
|
||||
|
||||
Used by terraria@.service:
|
||||
journal-access let the terraria group read the servers' journal
|
||||
prepare <name> create dirs/configs, unpack server if needed
|
||||
run <name> exec the server
|
||||
stop <name> <mainpid> graceful shutdown via console "exit" (service only;
|
||||
@@ -312,13 +314,106 @@ cmd_stop() {
|
||||
log "server did not exit within ${STOP_TIMEOUT}s; leaving it to systemd"
|
||||
}
|
||||
|
||||
# The servers log to their own journal (LogNamespace=terraria), which the
|
||||
# 'terraria' group can read; see cmd_journal_access. It lives in
|
||||
# <machine-id>.terraria under /var/log/journal (or /run/log/journal).
|
||||
journal_dirs() {
|
||||
local mid base
|
||||
mid=$(cat /etc/machine-id 2>/dev/null) || return 0
|
||||
[[ -n $mid ]] || return 0
|
||||
for base in /var/log/journal /run/log/journal; do
|
||||
if [[ -d $base/$mid.$JOURNAL_NS ]]; then printf '%s\n' "$base/$mid.$JOURNAL_NS"; fi
|
||||
done
|
||||
}
|
||||
|
||||
# Checks the actual permissions rather than guessing from group names. The
|
||||
# folder itself is world-readable, so the journal file inside is what counts.
|
||||
# No folder or file yet means nothing has been logged, so nothing to hide.
|
||||
can_read_journal() {
|
||||
if [[ $EUID -eq 0 ]]; then return 0; fi
|
||||
local d
|
||||
while IFS= read -r d; do
|
||||
if [[ ! -r $d || ! -x $d ]]; then return 1; fi
|
||||
if [[ -e $d/system.journal && ! -r $d/system.journal ]]; then return 1; fi
|
||||
done < <(journal_dirs)
|
||||
return 0
|
||||
}
|
||||
|
||||
journal_hint() {
|
||||
{
|
||||
echo "Note: commands are sent, but you can't see the server's output."
|
||||
if [[ " $(id -Gn) " == *" $SVC_USER "* ]]; then
|
||||
echo "You're in the '$SVC_USER' group, but the servers' journal isn't set up for it"
|
||||
echo "yet. That happens automatically when a server (re)starts, or run once:"
|
||||
echo " sudo terractl journal-access"
|
||||
else
|
||||
echo "Reading it needs root or the '$SVC_USER' group. If you were just added to it,"
|
||||
echo "log out and back in. Or use sudo."
|
||||
fi
|
||||
} >&2
|
||||
}
|
||||
|
||||
# Run as root before every server start (ExecStartPre=+ in terraria@.service).
|
||||
# Creates the servers' journal folder so it can be given to the terraria group
|
||||
# before journald writes to it, then applies the access rules from tmpfiles.d
|
||||
# (which also repair files journald created earlier). Only creates the folder
|
||||
# where journald already keeps journals: creating /var/log/journal itself would
|
||||
# switch the whole system to persistent logging. Never blocks a server start.
|
||||
cmd_journal_access() {
|
||||
[[ $EUID -eq 0 ]] || die "journal-access must run as root"
|
||||
local mid base
|
||||
mid=$(cat /etc/machine-id 2>/dev/null) || return 0
|
||||
[[ -n $mid ]] || return 0
|
||||
for base in /var/log/journal /run/log/journal; do
|
||||
if [[ -d $base && ! -d $base/$mid.$JOURNAL_NS ]]; then
|
||||
# inherits journald's group (systemd-journal) through the setgid parent
|
||||
mkdir -m 0755 "$base/$mid.$JOURNAL_NS" 2>/dev/null ||
|
||||
log "warning: could not create $base/$mid.$JOURNAL_NS"
|
||||
fi
|
||||
done
|
||||
systemd-tmpfiles --create --prefix=/var/log/journal --prefix=/run/log/journal \
|
||||
terractl.conf 2>/dev/null || log "warning: could not set journal access for group '$SVC_USER'"
|
||||
}
|
||||
|
||||
cmd_cmd() {
|
||||
local name=$1; shift
|
||||
[[ $# -gt 0 ]] || die "no console command given"
|
||||
local fifo="$RUN_DIR/$name.stdin"
|
||||
local fifo="$RUN_DIR/$name.stdin" unit="terraria@$name" cursor="" out="" prev=-1 quiet=0 i
|
||||
[[ -p $fifo ]] || die "$fifo not found - is terraria@$name running?"
|
||||
[[ -w $fifo ]] || die "no write access to $fifo (run with sudo or join group '$SVC_USER')"
|
||||
|
||||
if ! can_read_journal; then
|
||||
printf '%s\n' "$*" > "$fifo"
|
||||
echo "sent."
|
||||
journal_hint
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Note the journal position first, so only the reply to this command is shown
|
||||
cursor=$(journalctl --namespace="$JOURNAL_NS" -u "$unit" -n 1 --show-cursor -q -o cat 2>/dev/null |
|
||||
sed -n 's/^-- cursor: //p') || true
|
||||
local -a after=(--since=-2s)
|
||||
if [[ -n $cursor ]]; then after=(--after-cursor="$cursor"); fi
|
||||
printf '%s\n' "$*" > "$fifo"
|
||||
echo "sent. Output: journalctl -u terraria@$name -n 20"
|
||||
|
||||
# Show the server's output until it has been quiet for 1s (at most 5s)
|
||||
for ((i = 0; i < 50; i++)); do
|
||||
sleep 0.1
|
||||
out=$(journalctl --namespace="$JOURNAL_NS" -u "$unit" "${after[@]}" -q -o cat 2>/dev/null) || true
|
||||
if [[ -n $out && ${#out} -eq $prev ]]; then
|
||||
quiet=$((quiet + 1))
|
||||
if [[ $quiet -ge 10 ]]; then break; fi
|
||||
else
|
||||
quiet=0
|
||||
fi
|
||||
prev=${#out}
|
||||
done
|
||||
if [[ -n $out ]]; then
|
||||
printf '%s\n' "$out"
|
||||
else
|
||||
echo "sent; no output from the server within 5s (it may be busy or still starting)."
|
||||
echo "Watch it with: terractl attach $name"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_attach() {
|
||||
@@ -327,9 +422,13 @@ cmd_attach() {
|
||||
[[ -w $fifo ]] || die "no write access to $fifo (run with sudo or join group '$SVC_USER')"
|
||||
|
||||
echo "Attached to terraria@$name. Ctrl-D or Ctrl-C detaches; the server keeps running."
|
||||
# Server output comes from the journal; -o cat drops the timestamp prefixes.
|
||||
journalctl -u "terraria@$name" -f -n 30 -o cat &
|
||||
ATTACH_PID=$! # killed by cleanup() however attach ends
|
||||
if can_read_journal; then
|
||||
# Server output comes from the journal; -o cat drops the timestamp prefixes.
|
||||
journalctl --namespace="$JOURNAL_NS" -u "terraria@$name" -f -n 30 -o cat &
|
||||
ATTACH_PID=$! # killed by cleanup() however attach ends
|
||||
else
|
||||
journal_hint
|
||||
fi
|
||||
trap 'echo; exit 0' INT
|
||||
|
||||
# -e gives line editing and history while typing commands
|
||||
@@ -805,6 +904,7 @@ case $command in
|
||||
else echo "terractl $TERRACTL_VERSION"; fi
|
||||
exit 0 ;;
|
||||
list) cmd_list; exit ;;
|
||||
journal-access) cmd_journal_access; exit ;;
|
||||
esac
|
||||
[[ $# -ge 1 ]] || usage
|
||||
valid_name "$1"
|
||||
|
||||
Reference in new issue
Block a user