#!/bin/sh
# rollcall-overlay <system|runtime>
# Fetches this node's overlay tarball from the rollcall server (identified by
# the rollcall.node token on the kernel command line), applies it over / when
# it changed, then runs /run/rollcall/post-<stage>.sh if the overlay shipped one.
# With rollcall.tls= and rollcall.ca= on the command line it talks HTTPS: the
# CA certificate is accepted only by that SHA-256, and there is no fallback
# to HTTP (the overlay carries secrets such as munge.key).
set -eu
stage=${1:-system}
SERVER=""; TOKEN=""; TLS=""; CA=""
for t in $(cat /proc/cmdline); do
  case $t in
    rollcall.server=*) SERVER=${t#*=} ;;
    rollcall.node=*)   TOKEN=${t#*=} ;;
    rollcall.tls=*)    TLS=${t#*=} ;;
    rollcall.ca=*)     CA=$(echo "${t#*=}" | tr -d ':' | tr 'A-F' 'a-f') ;;
  esac
done
if [ -z "$SERVER" ] || [ -z "$TOKEN" ]; then
  echo "rollcall-overlay: rollcall.server/rollcall.node not on cmdline, nothing to do"
  exit 0
fi
mkdir -p /run/rollcall
CURL_CA=""
if [ -n "$TLS" ] && [ -n "$CA" ]; then
  cafile=/run/rollcall/ca.pem
  if [ ! -s "$cafile" ]; then
    i=0
    until curl -fsS --connect-timeout 5 "$SERVER/ca.pem" -o "$cafile.new"; do
      i=$((i+1)); [ "$i" -ge 30 ] && { echo "rollcall-overlay: cannot fetch the CA certificate" >&2; exit 1; }
      sleep 5
    done
    got=$(openssl x509 -in "$cafile.new" -outform DER | sha256sum | cut -d' ' -f1)
    if [ "$got" != "$CA" ]; then
      rm -f "$cafile.new"
      echo "rollcall-overlay: the CA certificate does not match rollcall.ca; not fetching the overlay" >&2
      exit 1
    fi
    mv -f "$cafile.new" "$cafile"
  fi
  SERVER=$TLS
  CURL_CA="--cacert $cafile"
fi
tmp=/run/rollcall/$stage.tar.new
i=0
# shellcheck disable=SC2086 # CURL_CA is two words or none
until curl -fsS --connect-timeout 5 $CURL_CA -H "X-Rollcall-Node: $TOKEN" \
      "$SERVER/api/v1/nodes/self/overlay?stage=$stage" -o "$tmp"; do
  i=$((i+1))
  if [ "$i" -ge 60 ]; then echo "rollcall-overlay: server unreachable" >&2; exit 1; fi
  sleep 5
done
new=$(sha256sum "$tmp" | cut -d' ' -f1)
old=$(cat "/run/rollcall/$stage.sha" 2>/dev/null || true)
if [ "$new" = "$old" ]; then
  rm -f "$tmp"
  exit 0
fi
tar -C / -xpf "$tmp" --no-same-owner --overwrite
mv -f "$tmp" "/run/rollcall/$stage.tar"
echo "$new" > "/run/rollcall/$stage.sha"
echo "rollcall-overlay: applied $stage overlay ($new)"
if [ -f "/run/rollcall/post-$stage.sh" ]; then
  sh "/run/rollcall/post-$stage.sh" || echo "rollcall-overlay: post-$stage.sh failed" >&2
fi
