#!/bin/bash # A Parent Call sanctuary that cannot reach the sanctuary. # # The real coordinator, from the control computer, running in the lab # against a broker on loopback and a ProPresenter that is a mock. The # church's own networks are rejected from inside the container first, so # a wrong host in a config file cannot put a child's name on the real # screen. Coordinator development has done that once already. # # tools/lab/parent-call-rig up [MODE] # off | approval | auto # tools/lab/parent-call-rig mode MODE # tools/lab/parent-call-rig approve|reject # tools/lab/parent-call-rig watch # tools/lab/parent-call-rig triggers # tools/lab/parent-call-rig down set -uo pipefail NAME="${LAB_NAME:-classroom-v2-lab}" SRC="${PARENT_CALL_SRC:-classroom-control:/home/media/docker/parent-call}" ROOT=classroom/parent-call inlab() { docker exec "$NAME" "$@"; } guard() { # Container-local. This netns belongs to the container alone, so # nothing on the host or the church network is changed by it. inlab sh -c ' iptables -C OUTPUT -d 10.30.0.0/16 -j REJECT 2>/dev/null || iptables -I OUTPUT -d 10.30.0.0/16 -j REJECT iptables -C OUTPUT -d 10.40.0.0/16 -j REJECT 2>/dev/null || iptables -I OUTPUT -d 10.40.0.0/16 -j REJECT' for target in 10.40.0.2/1883 10.30.0.2/1025; do if inlab timeout 4 sh -c "exec 3<>/dev/tcp/${target}" 2>/dev/null; then echo "REFUSING TO CONTINUE: ${target} is still reachable" >&2 exit 1 fi done echo " church networks unreachable from the lab" } case "${1:-up}" in up) mode="${2:-approval}" inlab sh -c 'apt-get install -y -qq --no-install-recommends \ mosquitto mosquitto-clients python3-paho-mqtt iptables >/dev/null 2>&1' guard inlab sh -c 'mkdir -p /opt/pc-test' ssh -o BatchMode=yes "${SRC%%:*}" "cd ${SRC#*:} && tar cf - src" \ | docker exec -i "$NAME" sh -c 'cd /opt/pc-test && tar xf -' echo " coordinator source copied from the control computer" docker exec -i "$NAME" sh -c 'cat > /opt/pc-test/mosquitto.conf' < /opt/pc-test/coordinator.env' < /opt/propresenter-mock.py' \ < "$(dirname "$0")/propresenter-mock.py" # Debian's own mosquitto unit would listen where the lab does not want # it to. The rig runs its own, on loopback, and nothing else. inlab sh -c 'systemctl disable --now mosquitto >/dev/null 2>&1; pkill -f propresenter-mock; pkill -f parent_call.main; pkill mosquitto; fuser -k 1025/tcp 1883/tcp 2>/dev/null; true' sleep 3 inlab sh -c 'setsid mosquitto -c /opt/pc-test/mosquitto.conf > /tmp/mosquitto.log 2>&1 &' inlab sh -c 'setsid python3 /opt/propresenter-mock.py 1025 > /tmp/ppmock.log 2>&1 &' sleep 2 inlab sh -c 'cd /opt/pc-test && set -a && . ./coordinator.env && set +a && setsid env PYTHONPATH=/opt/pc-test/src python3 -m parent_call.main \ > /tmp/coordinator.log 2>&1 &' sleep 4 # The room points at the loopback broker, never at the church's. # docker exec needs -i or the heredoc reaches nothing at all, which is # how this silently left the room pointing nowhere. docker exec -i "$NAME" python3 - <<'PY' import pathlib p = pathlib.Path("/etc/ekklesia-classroom/device.conf") t = p.read_text() t = t.replace("MQTT_ENABLED=false", "MQTT_ENABLED=true") if "MQTT_HOST=127.0.0.1" not in t: t = t.replace("MQTT_HOST=", "MQTT_HOST=127.0.0.1", 1) if "\nROOM=" not in t: t += "\n# Lab only.\nROOM=nursery\n" p.write_text(t) PY "$0" mode "$mode" inlab tail -3 /tmp/coordinator.log echo " rig up in mode $mode" ;; mode) inlab mosquitto_pub -h 127.0.0.1 -t "$ROOT/mode/set" -m "${2:?mode}" sleep 1 echo -n " mode is now: " inlab timeout 3 mosquitto_sub -h 127.0.0.1 -t "$ROOT/mode" -C 1 || true ;; approve|reject) id=$(inlab timeout 3 mosquitto_sub -h 127.0.0.1 -t "$ROOT/pending" -C 1 | python3 -c 'import json,sys; print(json.load(sys.stdin).get("id") or "")') [ -n "$id" ] || { echo " nothing is waiting"; exit 0; } inlab mosquitto_pub -h 127.0.0.1 -t "$ROOT/$1" -m "{\"id\": \"$id\"}" echo " $1ed $id" ;; watch) inlab mosquitto_sub -h 127.0.0.1 -t "$ROOT/#" -v ;; triggers) inlab sh -c 'cat /tmp/propresenter-mock.log 2>/dev/null || echo "(none)"' ;; log) inlab tail -n "${2:-25}" /tmp/coordinator.log ;; down) inlab sh -c 'pkill -f parent_call.main; pkill -f propresenter-mock; pkill mosquitto; true' echo " rig down" ;; *) sed -n '2,14p' "$0" exit 1 ;; esac