#!/usr/bin/env bash # Smoke-test the shared MQTT broker (LXC 104 · hotel-manage-mqtt-broker). # # Verifies the broker actually authenticates and round-trips messages, not # just that the process is up: creates a throwaway dynsec client + role # scoped to a private "smoketest/#" topic, publishes a retained message, # confirms it's delivered back via subscribe, then deletes the throwaway # client/role again. Also checks that a bogus login is rejected, proving # allow_anonymous=false is actually enforced. # # Run on the Proxmox host: # bash <(curl -fsSL https://git.pterois.co.uk/hotel-manage-stack/stack-init/raw/branch/main/scripts/test-mqtt-broker.sh) set -euo pipefail CREDS_FILE=/root/hotel-manage-credentials.txt [[ -f "$CREDS_FILE" ]] || { echo "No credentials file at $CREDS_FILE — has the stack been installed?"; exit 1; } MQTT_ADMIN_USER=$(sed -n 's/^MQTT_ADMIN_USER=//p' "$CREDS_FILE" | head -1) MQTT_ADMIN_PASS=$(sed -n 's/^MQTT_ADMIN_PASS=//p' "$CREDS_FILE" | head -1) [[ -n "$MQTT_ADMIN_USER" && -n "$MQTT_ADMIN_PASS" ]] || { echo "MQTT_ADMIN_USER/PASS not found in $CREDS_FILE — has the broker been deployed (--only mqtt-broker)?" exit 1 } pct exec 104 -- docker inspect hotel-manage-mqtt-broker &>/dev/null || { echo "Container hotel-manage-mqtt-broker not found on LXC 104 — is it deployed?" exit 1 } NET="--network container:hotel-manage-mqtt-broker" IMG="eclipse-mosquitto:2" TEST_USER="smoketest-$$" TEST_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c 18) TEST_ROLE="smoketest-role-$$" TOPIC="smoketest/$$" PAYLOAD="hello-$$" ctrl() { pct exec 104 -- docker run --rm $NET "$IMG" \ mosquitto_ctrl -h 127.0.0.1 -p 1883 -u "$MQTT_ADMIN_USER" -P "$MQTT_ADMIN_PASS" dynsec "$@" 2>/dev/null } cleanup() { ctrl deleteClient "$TEST_USER" &>/dev/null || true ctrl deleteRole "$TEST_ROLE" &>/dev/null || true } trap cleanup EXIT echo "== Creating throwaway client + role scoped to ${TOPIC} ==" ctrl createClient "$TEST_USER" -p "$TEST_PASS" ctrl createRole "$TEST_ROLE" ctrl addRoleACL "$TEST_ROLE" publishClientSend "$TOPIC" allow ctrl addRoleACL "$TEST_ROLE" publishClientReceive "$TOPIC" allow ctrl addRoleACL "$TEST_ROLE" subscribePattern "$TOPIC" allow ctrl addClientRole "$TEST_USER" "$TEST_ROLE" echo "== Publishing retained test message ==" pct exec 104 -- docker run --rm $NET "$IMG" \ mosquitto_pub -h 127.0.0.1 -p 1883 -u "$TEST_USER" -P "$TEST_PASS" -t "$TOPIC" -m "$PAYLOAD" -r echo "== Subscribing to confirm delivery ==" RESULT=$(pct exec 104 -- docker run --rm $NET "$IMG" \ mosquitto_sub -h 127.0.0.1 -p 1883 -u "$TEST_USER" -P "$TEST_PASS" -t "$TOPIC" -C 1 -W 10 2>/dev/null || true) echo "== Clearing retained message ==" pct exec 104 -- docker run --rm $NET "$IMG" \ mosquitto_pub -h 127.0.0.1 -p 1883 -u "$TEST_USER" -P "$TEST_PASS" -t "$TOPIC" -n -r echo "== Confirming a bogus login is rejected (allow_anonymous=false) ==" if pct exec 104 -- docker run --rm $NET "$IMG" \ mosquitto_pub -h 127.0.0.1 -p 1883 -u "not-a-real-user" -P "wrong-password" -t "$TOPIC" -m "x" &>/dev/null; then echo "FAIL — bogus credentials were accepted, broker auth is not enforced" exit 1 fi echo " ok — bogus credentials rejected" if [[ "$RESULT" == "$PAYLOAD" ]]; then echo echo "PASS — broker authenticated the throwaway client and round-tripped '$PAYLOAD'" else echo echo "FAIL — expected payload '$PAYLOAD', got: '$RESULT'" exit 1 fi