#!/bin/sh # on_start hook (provider: mosquitto). # # Runs INSIDE the mosquitto container on EVERY boot, before the consumer's # container starts (reconcile visits providers first). Must be idempotent. # # Job: make sure the consumer's MQTT account still exists. The common path is # a no-op — the passwd file lives on a persistent volume and survives reboots. # This only does work if the account went missing (e.g. the data volume was # wiped), in which case it restores the SAME password the consumer holds. It # never rotates a live password, so the consumer's stored MQTT_PASS keeps # working. # # Where the password comes from: # - Core that injects consumer .env into on_start hooks hands it to us as # $FURTKA_CONSUMER_ENV_MQTT_PASS — the clean path. # - Older core gives on_start no consumer context, so we fall back to the # copy provision-client.sh stashed on our own volume at install time. # This hook's stdout is discarded by the reconciler (unlike on_install), so # restoring the password is the only way to keep the consumer connectable. # Errors go to stderr and fail the hook, which makes reconcile skip the # consumer's `compose up` rather than start it with a broken account. set -eu user="${FURTKA_CONSUMER_APP:?ensure-client: FURTKA_CONSUMER_APP not set}" passwd_file=/mosquitto/data/passwd stash="/mosquitto/data/furtka-clients/${user}.pw" # Account already present → nothing to do. if [ -f "$passwd_file" ] && grep -q "^${user}:" "$passwd_file"; then exit 0 fi pass="${FURTKA_CONSUMER_ENV_MQTT_PASS:-}" if [ -z "$pass" ] && [ -f "$stash" ]; then pass="$(cat "$stash")" fi if [ -z "$pass" ]; then echo "ensure-client: account '${user}' is missing and no password is" \ "available to restore it (no FURTKA_CONSUMER_ENV_MQTT_PASS, no stash);" \ "reinstall the app to re-provision." >&2 exit 1 fi mosquitto_passwd -b "$passwd_file" "$user" "$pass" kill -HUP 1 2>/dev/null || true