#!/bin/bash
# /usr/libexec/arrakis2frames
# All configuration arrives via the environment, from
# /etc/sysconfig/arrakis2frames[-<instance>].
# Usage: arrakis2frames [--dry-run]
set -euo pipefail

dry_run=0
[[ ${1:-} == --dry-run ]] && dry_run=1

: "${CTR_NAME:?not set}"
: "${IMAGE:?not set}"
: "${OUTDIR:?not set}"
: "${CHANNELS:?not set}"
: "${FRAME_DESCRIPTION:?not set}"
# REPLAY_ID: optional. Unset or empty means live data (no --replay-id).

: "${RUNAS:=arrakis}"
: "${DATA_ROOT:=/kafka/arrakis}"
: "${CID_FILE:=/run/${CTR_NAME}.ctr-id}"
: "${FRAME_DURATION:=1}"
: "${RETENTION_TIME:=300}"
: "${PULL_POLICY:=missing}"
: "${CGROUP_PARENT:=igwn_connect.slice}"
# MEMORY_LIMIT, MEMORY_SWAP, CPU_LIMIT, PIDS_LIMIT: optional, no defaults.

# Run the container detached. In the foreground, "podman run" stays resident
# only to proxy stdio and relay the exit status -- neither of which is needed
# here, because --log-driver=journald means conmon forwards the output. It is a
# Go binary, so that idle process costs 50-80 MB per instance.
#
# With --detach, podman exits once the container is up and conmon becomes the
# service's main process: --sdnotify=conmon makes conmon send both MAINPID= and
# READY=1, and NotifyAccess=all in the unit lets systemd accept them from a
# process it did not spawn. This is the same arrangement "podman generate
# systemd --new" and Quadlet emit.
#
# Defaults to false so upgrading the package does not change the behaviour of a
# running fleet. Enable per site, or per instance, after testing on each OS and
# podman version present:  PODMAN_DETACH=true
#
# If the handover ever failed, systemd would see the main process exit without
# READY= and fail the unit immediately ("Failed with result 'protocol'"). There
# is no mode where the container runs while systemd tracks the wrong process.
: "${PODMAN_DETACH:=false}"

uid=$(id -u "$RUNAS")
gid=$(id -g "$RUNAS")

# Intentional word splitting; globbing off so a stray '*' cannot expand.
set -f
# shellcheck disable=SC2206
channels=($CHANNELS)
extra=(${EXTRA_ARGS:-})
set +f
[[ ${#channels[@]} -gt 0 ]] || { echo "CHANNELS is empty" >&2; exit 1; }

# Optional resource limits: emitted only when set to a non-empty value.
limits=()
if [[ -n ${MEMORY_LIMIT:-} ]]; then
  limits+=(--memory="$MEMORY_LIMIT")
  # --memory-swap is the memory+swap TOTAL. Equal to --memory means no swap
  # allowance. Podman's default when omitted is 2x --memory, so this fallback
  # matters on any node that has swap enabled.
  limits+=(--memory-swap="${MEMORY_SWAP:-$MEMORY_LIMIT}")
elif [[ -n ${MEMORY_SWAP:-} ]]; then
  echo "MEMORY_SWAP set without MEMORY_LIMIT; ignoring" >&2
fi
[[ -n ${CPU_LIMIT:-}  ]] && limits+=(--cpus="$CPU_LIMIT")
[[ -n ${PIDS_LIMIT:-} ]] && limits+=(--pids-limit="$PIDS_LIMIT")

flags=()
[[ -n ${REPLAY_ID:-}    ]] && flags+=(--replay-id "$REPLAY_ID")
[[ -n ${SKIP_ALL_GAP:-} ]] && flags+=("$SKIP_ALL_GAP")
[[ -n ${VERBOSE:-}      ]] && flags+=("$VERBOSE")

# Accept the usual spellings, and complain about anything else rather than
# silently running in the foreground because someone wrote "PODMAN_DETACH=Y".
detach=()
case ${PODMAN_DETACH,,} in
  true|yes|on|1)   detach=(--detach) ;;
  false|no|off|0|"") ;;
  *) echo "PODMAN_DETACH='${PODMAN_DETACH}' not recognised; running in the foreground" >&2 ;;
esac

cmd=(
  /usr/bin/podman run
    "${detach[@]}"
    --rm --replace --name "$CTR_NAME"
    --pull="$PULL_POLICY"
    --cidfile="$CID_FILE"
    --sdnotify=conmon --cgroups=no-conmon
    --cgroup-parent="$CGROUP_PARENT"
    --user "${uid}:${gid}"
    "${limits[@]}"
    --log-driver=journald
    --net=host
    --env ARRAKIS_SERVER
    --cap-drop=ALL --security-opt=no-new-privileges
    -v "${DATA_ROOT}:${DATA_ROOT}"
    "$IMAGE"
    --source arrakis --sink frames
    --channels "${channels[@]}"
    --frame-duration "$FRAME_DURATION"
    --output-dir "$OUTDIR"
    --frame-description "$FRAME_DESCRIPTION"
    --retention-time "$RETENTION_TIME"
    "${flags[@]}" "${extra[@]}"
)

# Record argv in the journal (stderr), then hand off.
{ printf 'exec:'; printf ' %q' "${cmd[@]}"; printf '\n'; } >&2

(( dry_run )) && exit 0
exec "${cmd[@]}"
