Skip to content

Commit

Permalink
+logs +ports +dbus interface
Browse files Browse the repository at this point in the history
  • Loading branch information
dubo-dubon-duponey committed Mar 21, 2024
1 parent a2ec22d commit f6027d4
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 291 deletions.
41 changes: 33 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ RUN --mount=type=secret,uid=100,id=CA \
apt-get install -qq --no-install-recommends \
libssl-dev:"$DEB_TARGET_ARCH"=3.0.11-1~deb12u2 \
libavahi-client-dev:"$DEB_TARGET_ARCH"=0.8-10 \
avahi-daemon:"$DEB_TARGET_ARCH"=0.8-10
avahi-daemon:"$DEB_TARGET_ARCH"=0.8-10 \
libglib2.0-dev:"$DEB_TARGET_ARCH"

# Bring in runtime dependencies
# avutil would be dragging in: libavutil56 libbsd0 libdrm-common libdrm2 libmd0 libva-drm2 libva-x11-2 libva2 libvdpau1 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxext6 libxfixes3 ocl-icd-libopencl1
Expand Down Expand Up @@ -186,6 +187,7 @@ RUN eval "$(dpkg-architecture -A "$(echo "$TARGETARCH$TARGETVARIANT" |
--with-os=linux \
--with-convolution \
--with-soxr \
--with-dbus-interface \
--sysconfdir="$XDG_CONFIG_DIRS"/shairport-sync \
--without-configfiles \
--without-sndio \
Expand All @@ -194,7 +196,6 @@ RUN eval "$(dpkg-architecture -A "$(echo "$TARGETARCH$TARGETVARIANT" |
--without-ao \
--without-jack \
--without-soundio \
--without-dbus-interface \
--without-dbus-test-client \
--without-mpris-interface \
--without-mpris-test-client \
Expand Down Expand Up @@ -290,9 +291,15 @@ RUN --mount=type=secret,uid=100,id=CA \
&& rm -rf /tmp/* \
&& rm -rf /var/tmp/*

# Deviate avahi temporary files into /tmp (there is a socket, so, probably need exec). Avahi is also braindead and requires the folder to belong to user avahi
# even if started with a different user.
RUN mkdir -p "$XDG_STATE_HOME"/avahi-daemon; ln -s "$XDG_STATE_HOME"/avahi-daemon /run; chown avahi:avahi /run/avahi-daemon; chmod 777 /run/avahi-daemon
# Deviate avahi temporary files into state. \
# Avahi is also just braindead and requires the folder to belong to user avahi even if run with a different user.
# Also, it does not seem possible to override the dbus socket location with environment variables - and shairport is not happy with the custom config location
# So... back on the system config, but twist it.
RUN mkdir -p "$XDG_STATE_HOME"/avahi-daemon; ln -s "$XDG_STATE_HOME"/avahi-daemon /run; chown avahi:avahi /run/avahi-daemon; chmod 777 /run/avahi-daemon; \
sed -Ei "s/[/]run[/]dbus[/]system_bus_socket/\/magnetar\/runtime\/dbus\/system_bus_socket/" /usr/share/dbus-1/system.conf; \
sed -Ei 's/user="avahi"/user="dubo-dubon-duponey"/' /usr/share/dbus-1/system.d/avahi-dbus.conf

# sed -Ei 's/deny own/allow own/' /usr/share/dbus-1/system.conf; \

USER dubo-dubon-duponey

Expand Down Expand Up @@ -326,10 +333,28 @@ EXPOSE $ADVANCED_AIRPLAY_PORT/tcp
EXPOSE 319
EXPOSE 320

# RTSP port

## Both protocols
# Obviously 5353 for the mDNS listener
EXPOSE 5353
# RTSP (main advertised) port for both Airplay 1 and 2 (overriden by --port in entrypoint - airplay one is supposed to be 5000)
EXPOSE 7000
# UDP port range
EXPOSE 6001-6011/udp

## Airplay 2 only
# DAAP port (https://en.wikipedia.org/wiki/Digital_Audio_Access_Protocol)
EXPOSE 3689/tcp
# PTP ports (https://en.wikipedia.org/wiki/Precision_Time_Protocol)
EXPOSE 319:320/udp
# XXX Documentation claims that port 5000/tcp is used as well, on top of "port=7000" - is that a copypaste error?
#EXPOSE 5000/tcp
# Ephemeral ports - technically do not need to be exposed
# EXPOSE 32768:60999

## Airplay 1 only
# UDP port range for Airplay 1 only
EXPOSE 6000:6009/udp
# XXX Documentation also claims that 3689/tcp is used by airplay 1 but...
# EXPOSE 3689/tcp

VOLUME "$XDG_RUNTIME_DIR"
VOLUME "$XDG_CACHE_HOME"
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ These reasons could be that you are interested in:
* observable
* [x] healthcheck
* [x] logs to stdout
* [ ] ~~prometheus endpoint~~
* [ ] ~~prometheus endpoint~~ not applicable - one should rather monitor containers using a dedicated prometheus endpoint

## Run

Expand Down Expand Up @@ -59,7 +59,7 @@ The following environment variables allow for high-level control over shairport:
* MOD_MDNS_NAME controls the announced name
* OUTPUT (alsa|pipe|stdout) controls the output
* DEVICE (example: `default:CARD=Mojo`) controls the output device (default to "default")
* LOG_LEVEL if set to "debug" will pass along `-vvv` and `--statistics` to shairport (noisy!)
* LOG_LEVEL - debug, info, warning, error
* ADVANCED_AIRPLAY_PORT controls the port to bind to (defaults to 7000)
* STUFFING (basic or soxr) controls the stuffing mode (see soxr section below)

Expand All @@ -75,8 +75,10 @@ This is specifically convenient to address a different mixer.

### Custom configuration file

For more advanced control over `shairport-sync` configuration, mount `/magnetar/user/config/shairport-sync/main.conf`
and just add whichever configuration you want aggregated to the default one.
For more advanced control over `shairport-sync` configuration:
* mount `/magnetar/user/config/shairport-sync/main.conf`.
* make sure permissions are fine: `chown 2000`
* add whichever configuration you want aggregated to the default configuration

### About soxr

Expand All @@ -95,6 +97,7 @@ Therefore, we switched back to avahi/dbus, hopefully run with a non-root user an
### About other options

We compile only for alsa, and disabled a number of optional features.

See the Dockerfile for details.

## Moar?
Expand Down
43 changes: 34 additions & 9 deletions context/runtime/boot/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,40 @@ readonly root
# shellcheck source=/dev/null
. "$root/mdns.sh"

helpers::logger::set "$LOG_LEVEL"

helpers::logger::log INFO "[entrypoint]" "Starting container"

helpers::logger::log DEBUG "[entrypoint]" "Checking directories permissions"
helpers::dir::writable "$XDG_RUNTIME_DIR/dbus" create
helpers::dir::writable "$XDG_RUNTIME_DIR/shairport-sync" create
helpers::dir::writable "$XDG_CACHE_HOME/shairport-sync" create
helpers::dir::writable "$XDG_STATE_HOME/avahi-daemon"

mdns::start::dbus
mdns::start::avahi
helpers::logger::log INFO "[entrypoint]" "Starting dbus"
mdns::start::dbus "$LOG_LEVEL"

helpers::logger::log INFO "[entrypoint]" "Starting avahi"
mdns::start::avahi "$LOG_LEVEL"

nqptp &
helpers::logger::log INFO "[entrypoint]" "Starting nqptp"

{
nqptp 2>&1
} > >(helpers::logger::slurp "$LOG_LEVEL" "[nqptp]") \
&& helpers::logger::log INFO "[nqptp]" "nqptp stopped" \
|| helpers::logger::log ERROR "[nqptp]" "nqptp stopped with exit code: $?" &

helpers::logger::log DEBUG "[entrypoint]" "Preparing configuration"
[ "${MOD_MQTT_ENABLED:-}" == true ] && MOD_MQTT_ENABLED=yes || MOD_MQTT_ENABLED=no
[ "${MOD_MQTT_COVER:-}" == true ] && MOD_MQTT_COVER=yes || MOD_MQTT_COVER=no

configuration="$(cat "$XDG_CONFIG_DIRS"/shairport-sync/main.conf)"
[ ! -e "$XDG_CONFIG_HOME"/shairport-sync/main.conf ] || configuration+="$(cat "$XDG_CONFIG_HOME"/shairport-sync/main.conf)"

env


# shellcheck disable=SC2016
configuration+="$(printf '
Expand Down Expand Up @@ -53,15 +71,17 @@ mqtt = {
"$MOD_MQTT_ENABLED" \
"${MOD_MQTT_HOST:-}" \
"${MOD_MQTT_PORT:-1883}" \
"${MOD_MQTT_USER:-NULL}" \
"${MOD_MQTT_PASSWORD:-NULL}" \
"${MOD_MQTT_CA:-NULL}" \
"${MOD_MQTT_CERT:-NULL}" \
"${MOD_MQTT_KEY:-NULL}" \
"${MOD_MQTT_USER:-}" \
"${MOD_MQTT_PASSWORD:-}" \
"${MOD_MQTT_CA:-}" \
"${MOD_MQTT_CERT:-}" \
"${MOD_MQTT_KEY:-}" \
"$MOD_MQTT_COVER")"

printf "%s" "$configuration" > "$XDG_RUNTIME_DIR"/shairport-sync/main.conf
helpers::logger::log DEBUG "[entrypoint]" "Configuration finalized: $configuration"

helpers::logger::log DEBUG "[entrypoint]" "Preparing command"
# https://github.com/mikebrady/shairport-sync/blob/master/scripts/shairport-sync.conf
args=(\
--name "$MOD_MDNS_NAME" \
Expand All @@ -78,4 +98,9 @@ args=(\
args+=("$@")
[ ! "$DEVICE" ] || [ "$OUTPUT" != "alsa" ] || args+=(-- -d "$DEVICE")

exec shairport-sync "${args[@]}"
helpers::logger::log DEBUG "[entrypoint]" "Command ready to execute - handing over now:"
helpers::logger::log INFO "[entrypoint]" "Starting: shairport-sync ${args[*]}"
# Slurp logs at log_level and relog properly
{
exec shairport-sync "${args[@]}" 2>&1
} > >(helpers::logger::slurp "$LOG_LEVEL" "[shairport-sync]")
67 changes: 67 additions & 0 deletions context/runtime/boot/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,70 @@ helpers::log::normalize(){
}

helpers::log::normalize >/dev/null

# shellcheck disable=SC2034
readonly DC_COLOR_BLACK=0
# shellcheck disable=SC2034
readonly DC_COLOR_RED=1
# shellcheck disable=SC2034
readonly DC_COLOR_GREEN=2
# shellcheck disable=SC2034
readonly DC_COLOR_YELLOW=3
# shellcheck disable=SC2034
readonly DC_COLOR_BLUE=4
# shellcheck disable=SC2034
readonly DC_COLOR_MAGENTA=5
# shellcheck disable=SC2034
readonly DC_COLOR_CYAN=6
# shellcheck disable=SC2034
readonly DC_COLOR_WHITE=7
# shellcheck disable=SC2034
readonly DC_COLOR_DEFAULT=9

# shellcheck disable=SC2034
readonly DC_LOGGER_DEBUG=4
# shellcheck disable=SC2034
readonly DC_LOGGER_INFO=3
# shellcheck disable=SC2034
readonly DC_LOGGER_WARNING=2
# shellcheck disable=SC2034
readonly DC_LOGGER_ERROR=1

export DC_LOGGER_STYLE_DEBUG=( setaf "$DC_COLOR_WHITE" )
export DC_LOGGER_STYLE_INFO=( setaf "$DC_COLOR_GREEN" )
export DC_LOGGER_STYLE_WARNING=( setaf "$DC_COLOR_YELLOW" )
export DC_LOGGER_STYLE_ERROR=( setaf "$DC_COLOR_RED" )

_DC_PRIVATE_LOGGER_LEVEL="$DC_LOGGER_WARNING"

helpers::logger::log(){
local prefix="$1"
shift

local level="DC_LOGGER_$prefix"
local style="DC_LOGGER_STYLE_${prefix}[@]"

[ "$_DC_PRIVATE_LOGGER_LEVEL" -ge "${!level}" ] || return 0

# If you wonder about why that crazy shit: https://stackoverflow.com/questions/12674783/bash-double-process-substitution-gives-bad-file-descriptor
exec 3>&2
[ ! "$TERM" ] || [ ! -t 2 ] || >&2 tput "${!style}" 2>/dev/null || true
>&2 printf "[%s] [%s] %s\n" "$(date 2>/dev/null || true)" "$prefix" "$*"
[ ! "$TERM" ] || [ ! -t 2 ] || >&2 tput op 2>/dev/null || true
exec 3>&-
}

helpers::logger::set() {
local desired
desired="$(printf "DC_LOGGER_%s" "${1:-warning}" | tr '[:lower:]' '[:upper:]')"
_DC_PRIVATE_LOGGER_LEVEL="${!desired}"
}

helpers::logger::slurp(){
local level
level="$(printf "%s" "${1:-warning}" | tr '[:lower:]' '[:upper:]')"
shift
while read -r line; do
helpers::logger::log "$level" "$* $line";
done </dev/stdin
}
39 changes: 28 additions & 11 deletions context/runtime/boot/mdns.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,38 +69,45 @@ mdns::start::broadcaster(){

mdns::start::avahi(){
# Current issues with Avahi:
# - no way to change /run/avahi-daemon to another location - symlink works though
# - no way to change /run/avahi-daemon to another location - symlink works though (has to happen in the Dockerfile obviously)
# - daemonization writing to syslog is a problem
# - avahi insists that /run/avahi-daemon must belong to avahi:avahi
# which is absolutely ridiculous - https://github.com/lathiat/avahi/blob/778fadb71cb923eee74f3f1967db88b8c2586830/avahi-daemon/main.c#L1434
# Some variant of it: https://github.com/lathiat/avahi/issues/349
# - project is half-dead: https://github.com/lathiat/avahi/issues/388
# - project is half-dead anyway: https://github.com/lathiat/avahi/issues/388

local log_level="$1"
local args=()
# local avahisocket="$XDG_STATE_HOME/avahi-daemon/socket"
# XXX giving up on trying to be fancy with avahi
local avahisocket="/run/avahi-daemon/socket"

# Make sure we can write it
helpers::dir::writable "$(dirname "$avahisocket")" true
helpers::dir::writable "$(dirname "$avahisocket")"

# Cleanup leftovers on container restart
rm -f "$(dirname "$avahisocket")/pid"

[ "$LOG_LEVEL" != "debug" ] || args+=(--debug)
[ "$log_level" != "debug" ] || args+=(--debug)

# -D/--daemonize implies -s/--syslog that we do not want, so, just background it
avahi-daemon -f "$XDG_CONFIG_DIRS"/avahi/main.conf --no-drop-root --no-chroot "${args[@]}" &
{
{
avahi-daemon -f "$XDG_CONFIG_DIRS"/avahi/main.conf --no-drop-root --no-chroot "${args[@]}" 2>&1
} > >(helpers::logger::slurp "$log_level" "[avahi]") \
&& helpers::logger::log INFO "[avahi]" "Avahi stopped" \
|| helpers::logger::log ERROR "[avahi]" "Avahi stopped with exit code: $?"
} &


local tries=1
# Wait until the socket is there
until [ -e "$avahisocket" ]; do
sleep 1s
tries=$(( tries + 1))
[ $tries -lt 10 ] || {
printf >&2 "Failed starting avahi in a reasonable time. Something is quite wrong\n"
helpers::logger::log ERROR "[avahi]" "Failed starting avahi in a reasonable time. Something is quite wrong"
return 1
}
helpers::logger::log DEBUG "[avahi]" "Avahi started successfully"
done
}

Expand All @@ -109,6 +116,7 @@ mdns::start::dbus(){
# https://man7.org/linux/man-pages/man3/sd_bus_default.3.html
# https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html

local log_level="$1"
local dbussocket=/magnetar/runtime/dbus/system_bus_socket
# Configuration file also has that ^ hardcoded, so, cannot use the variable...

Expand All @@ -119,17 +127,26 @@ mdns::start::dbus(){
export DBUS_SYSTEM_BUS_ADDRESS=unix:path="$dbussocket"
export DBUS_SESSION_BUS_ADDRESS=unix:path="$dbussocket"

# Start it, without a PID file
dbus-daemon --nopidfile --config-file "$XDG_CONFIG_DIRS"/dbus/main.conf
# Start it, without a PID file, no fork
# XXX somehow right now shairport-sync is not happy - disable custom config for now
# dbus-daemon --nofork --nopidfile --nosyslog --config-file "$XDG_CONFIG_DIRS"/dbus/main.conf
{
{
dbus-daemon --system --nofork --nopidfile --nosyslog 2>&1
} > >(helpers::logger::slurp "$log_level" "[dbus]") \
&& helpers::logger::log INFO "[dbus]" "DBUS stopped" \
|| helpers::logger::log ERROR "[dbus]" "DBUS stopped with exit code: $?"
} &

local tries=1
# Wait until the socket is there
until [ -e "$dbussocket" ]; do
sleep 1s
tries=$(( tries + 1))
[ $tries -lt 10 ] || {
printf >&2 "Failed starting dbus in a reasonable time. Something is quite wrong\n"
helpers::logger::log ERROR "[dbus]" "Failed starting dbus in a reasonable time. Something is quite wrong"
return 1
}
done
helpers::logger::log DEBUG "[dbus]" "DBUS started successfully"
}
Loading

0 comments on commit f6027d4

Please sign in to comment.