Lets a *multi-instance-capable* app run as several fully isolated instances on one box (e.g. two Bookstack/WordPress sites, or a "family" + "work" Nextcloud) — distinct data, DB, subdomain, backups and update cadence. Design: an instance is just another app. It gets its own slug (<type>_<id>), its own CFG_<SLUG>_* namespace, deployed dir, DB row, IP/port allocation and host, so the entire existing pipeline (scan, install, services, routing, updater, backups) treats it like any app with zero changes. All instance-specific rewriting is confined to a clone of the type's template; the shipped template and the core engine are untouched. Gating: opt-in per app via CFG_<TYPE>_MULTI_INSTANCE=true. Only Bookstack carries it for now (the validated reference). The other 31 apps are unaffected — the feature is invisible unless the flag is present. - scripts/instance/instance_create.sh — clone + re-namespace config, rewrite compose identity (container_name / Traefik routers / backup labels) and per-app tools, set a hostname-safe subdomain (PORT field 10), then hand off to dockerInstallApp. Plus instanceList / instanceRemove. - libreportal instance create|remove|list — new CLI category; mutations route through the task system (no new mutating API endpoint). - WebUI: "instance of <type>" badge + a "New instance" card action on capable apps, and a create modal (name + domain# + subdomain, live host preview) that dispatches the standard task. Capability/instance-of read straight off the already-exposed app config. Known follow-ups (documented): flip the flag on more apps after a compose identity check (Nextcloud next); per-app tools are best-effort isolated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
57 lines
1.9 KiB
Bash
57 lines
1.9 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 type="$initial_command3"
|
|
local name="$initial_command4"
|
|
local domain_idx="$initial_command5"
|
|
local subdomain="$initial_command6"
|
|
|
|
case "$action" in
|
|
"create")
|
|
if [[ -z "$type" || -z "$name" ]]; then
|
|
isNotice "Usage: libreportal instance create <type> <name> [domain_index] [subdomain]"
|
|
cliShowInstanceHelp
|
|
return 1
|
|
fi
|
|
if [[ "$LIBREPORTAL_TASK_EXEC" == "1" ]]; then
|
|
instanceCreate "$type" "$name" "$domain_idx" "$subdomain"
|
|
else
|
|
local _cmd="libreportal instance create $type $name"
|
|
[[ -n "$domain_idx" ]] && _cmd+=" $domain_idx"
|
|
[[ -n "$subdomain" ]] && _cmd+=" $subdomain"
|
|
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
|
|
;;
|
|
|
|
*)
|
|
cliShowInstanceHelp
|
|
;;
|
|
esac
|
|
}
|