server-up/apps/unifi-network/files/init-mongo.sh
Ramon 3ee09eebc7
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 4m12s
fix(stacks): geslaagde wijziging niet meer terugdraaien
Het audit-logboek las request.remote_addr uit in de achtergrondthread van de
job. De RuntimeError die daarop volgde belandde in de foutafhandeling, die de
zojuist gemaakte backup terugzette — inclusief het oude compose-bestand.

- Adres vóór de threadstart vastleggen bij herconfigureren, koppelen, backup
  maken en terugrollen.
- UniFi: init-script probeert de beheerders 'unifi' en 'root' en herkent een
  server zonder authenticatie, zodat ook een oud Mongo-volume gerepareerd
  wordt; bestaande rollen blijven staan en 'backup'/'restore' worden aangevuld.
- UniFi: healthcheck van Mongo zonder inloggegevens, anders bleef de container
  ongezond en startte de reparatiecontainer nooit.
- Backups: mongodump/mongorestore gebruiken de beheerder uit compose in plaats
  van de verzonnen gebruiker 'app'.
- Appkaart: knop die de webinterface opent, met het adres uit /api/stacks.
- Joblog: geen dubbele regels meer doordat polls elkaar konden overlappen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H9Vcwu7owJZ3nj5dCf4VFT
2026-08-06 16:44:01 +02:00

105 lines
3.2 KiB
Bash
Executable file

<% raw %>
#!/bin/bash
set -e
if which mongosh > /dev/null 2>&1; then
mongo_init_bin="mongosh"
else
mongo_init_bin="mongo"
fi
mongo_args=()
if [[ -n "${MONGO_HOST:-}" ]]; then
mongo_args=(
--host "${MONGO_HOST}"
--port "${MONGO_PORT:-27017}"
)
fi
"${mongo_init_bin}" "${mongo_args[@]}" <<EOF
const beheerNaam = "${MONGO_INITDB_ROOT_USERNAME}";
const beheerWachtwoord = "${MONGO_INITDB_ROOT_PASSWORD}";
const appNaam = "${MONGO_USER}";
const appWachtwoord = "${MONGO_PASS}";
const authBron = "${MONGO_AUTHSOURCE}" || "admin";
const appDatabase = "${MONGO_DBNAME}";
const adminDb = db.getSiblingDB("admin");
// Welke beheerder in dit volume zit, hangt af van wie het heeft aangemaakt:
// het eerste sjabloon maakte 'unifi' aan, een later sjabloon 'root'. Daarom
// proberen we ze allemaal in plaats van er één te veronderstellen — anders
// mislukt de reparatie juist op de installaties die haar nodig hebben.
const kandidaten = [beheerNaam, appNaam, "root", "unifi"]
.filter((naam, i, alle) => naam && alle.indexOf(naam) === i);
function aanmelden() {
for (const naam of kandidaten) {
try {
if (adminDb.auth(naam, beheerWachtwoord)) {
return naam;
}
} catch (e) {
// Onbekende gebruiker of verkeerd wachtwoord: volgende kandidaat.
}
}
try {
// Draait deze server nog zonder authenticatie, dan mogen we zo verder.
adminDb.getUsers();
return "(zonder aanmelden)";
} catch (e) {
return "";
}
}
const beheerder = aanmelden();
if (!beheerder) {
print("");
print("FOUT: geen enkele MongoDB-beheerder kon inloggen op dit volume.");
print("Het wachtwoord in .env hoort niet bij de database die er al staat.");
print("Zet het oorspronkelijke wachtwoord terug in .env, of verwijder het");
print("volume om opnieuw te beginnen (dat wist wel je UniFi-gegevens).");
print("");
quit(18);
}
print("MongoDB-beheerder: " + beheerder);
const roles = [
{ db: "admin", role: "clusterMonitor" },
// Zonder deze twee kan Server Up geen mongodump/mongorestore draaien voor
// de backup van deze stack.
{ db: "admin", role: "backup" },
{ db: "admin", role: "restore" },
{ db: appDatabase, role: "dbOwner" },
{ db: appDatabase + "_stat", role: "dbOwner" },
{ db: appDatabase + "_audit", role: "dbOwner" },
{ db: appDatabase + "_restore", role: "dbOwner" }
];
function ensureUser(database) {
const userDb = db.getSiblingDB(database);
const bestaand = userDb.getUser(appNaam);
if (!bestaand) {
userDb.createUser({ user: appNaam, pwd: appWachtwoord, roles: roles });
print("Gebruiker " + appNaam + " aangemaakt in " + database + ".");
return;
}
// Alleen het wachtwoord gelijktrekken en ontbrekende rollen aanvullen. De
// rollen overschrijven zou de beheerder van een oudere installatie
// degraderen, waarna onder meer de backup geen dump meer kan maken.
userDb.updateUser(appNaam, { pwd: appWachtwoord });
const missend = roles.filter(
(r) => !(bestaand.roles || []).some((b) => b.role === r.role && b.db === r.db));
if (missend.length) {
userDb.grantRolesToUser(appNaam, missend);
}
print("Gebruiker " + appNaam + " bijgewerkt in " + database + ".");
}
ensureUser(authBron);
if (authBron !== appDatabase) {
ensureUser(appDatabase);
}
EOF
<% endraw %>