Fixing _instanceRewriteTools does nothing for an instance already on disk, and a clone from the old code is broken in ways that never announce themselves: every Tools action answers "App '<slug>' has no tool '<id>'" because dockerAppRunTool wants app<Ucfirst><Pascal>; `authPersistCfg <type>` writes the instance's new admin credential into the BASE app's config; and the clone defines the base app's adapter and tool names while its bodies exec against the instance's container, so the loader keeps whichever it sourced last and the base app's user tools can end up administering the instance — decided by nothing but find(1) order. Seen on a live install: the generated manifest resolved [appBookstackListUsers] to bookstack_test's copy. libreportal instance repair [slug] [--dry-run] Rewrites the template dir only — no container is touched, nothing reinstalled, so it does not route through the task system the way create/remove do. Idempotent by construction. Two of the three renames match their own output (appMattermost_teest… still starts with appMattermost), and a clone from the old code is only PARTLY wrong — its suffix hooks were always correct and end at the slug with no trailing underscore, which the infix rule would otherwise read as type + id + () and append the id twice (appSetupComposeTags_nextcloud_family_family). Three sentinels park the already-correct spellings before the rewrite and restore them after, so a healthy instance is a no-op and an interrupted run can just be re-run. Verified against fixtures built with the old rule set for all five multi-instance apps that ship tools: after repair each tree is byte-identical to a fresh clone from the fixed cloner, a second pass reports "already correct", and --dry-run leaves checksums untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
3.1 KiB
Bash
84 lines
3.1 KiB
Bash
#!/bin/bash
|
|
|
|
# Instance Commands Handler
|
|
# Multi-instance lifecycle for multi-instance-capable apps. Mutating verbs route
|
|
# through the task system (mirroring `app install`): the WebUI queues a task, the
|
|
# processor re-invokes the CLI with LIBREPORTAL_TASK_EXEC=1, and only then does
|
|
# the real work run. No new mutating backend API endpoint is introduced.
|
|
|
|
cliHandleInstanceCommands()
|
|
{
|
|
local action="$initial_command2"
|
|
|
|
# --local/--lan is pulled out of the positional list rather than given a fixed
|
|
# slot, so it can be written anywhere after the verb — `instance create
|
|
# bookstack home --local` reads naturally and still leaves domain#/subdomain
|
|
# in their documented positions for callers that pass them.
|
|
local local_only="false"
|
|
local -a _pos=()
|
|
local _a
|
|
for _a in "$initial_command3" "$initial_command4" "$initial_command5" \
|
|
"$initial_command6" "$initial_command7"; do
|
|
case "$_a" in
|
|
"--local"|"--lan") local_only="true" ;;
|
|
*) _pos+=("$_a") ;;
|
|
esac
|
|
done
|
|
|
|
local type="${_pos[0]}"
|
|
local name="${_pos[1]}"
|
|
local domain_idx="${_pos[2]}"
|
|
local subdomain="${_pos[3]}"
|
|
|
|
case "$action" in
|
|
"create")
|
|
if [[ -z "$type" || -z "$name" ]]; then
|
|
isNotice "Usage: libreportal instance create <type> <name> [domain_index] [subdomain] [--local]"
|
|
cliShowInstanceHelp
|
|
return 1
|
|
fi
|
|
if [[ "$LIBREPORTAL_TASK_EXEC" == "1" ]]; then
|
|
instanceCreate "$type" "$name" "$domain_idx" "$subdomain" "$local_only"
|
|
else
|
|
local _cmd="libreportal instance create $type $name"
|
|
[[ -n "$domain_idx" ]] && _cmd+=" $domain_idx"
|
|
[[ -n "$subdomain" ]] && _cmd+=" $subdomain"
|
|
# Re-invocation must carry the flag or the task-side run would
|
|
# silently build a Traefik-routed instance instead.
|
|
[[ "$local_only" == "true" ]] && _cmd+=" --local"
|
|
cliTaskRun "$_cmd" "install" "${type}_$(instanceIdPart "$name")"
|
|
fi
|
|
;;
|
|
|
|
"remove"|"delete")
|
|
# Here $type holds the instance slug (positional reuse).
|
|
local slug="$type"
|
|
if [[ -z "$slug" ]]; then
|
|
isNotice "Usage: libreportal instance remove <slug>"
|
|
return 1
|
|
fi
|
|
if [[ "$LIBREPORTAL_TASK_EXEC" == "1" ]]; then
|
|
instanceRemove "$slug"
|
|
else
|
|
cliTaskRun "libreportal instance remove $slug" "uninstall" "$slug"
|
|
fi
|
|
;;
|
|
|
|
"list")
|
|
instanceList "$type" # $type optional = filter by app type
|
|
;;
|
|
|
|
"repair")
|
|
# Rewrites files in the instance's TEMPLATE dir only — no container is
|
|
# touched, nothing is reinstalled — so it does not go through the task
|
|
# system the way create/remove do. $type holds the optional slug
|
|
# (positional reuse), $name an optional --dry-run.
|
|
instanceRepair "$type" "$name"
|
|
;;
|
|
|
|
*)
|
|
cliShowInstanceHelp
|
|
;;
|
|
esac
|
|
}
|