Make multi-instance actually install, and stop apps stealing each other's network rows
Instance install (bugs found by running one end to end): - The cloned compose kept the TYPE's tag namespace (#LIBREPORTAL|BOOKSTACK_APP_KEY_1_TAG|...) while the config had been re-namespaced to CFG_<SLUG>_*, so tagsProcessorAppConfigValues matched nothing, the placeholders survived and the pre-start guard refused to launch. Rewrite the tag names and *_DATA tokens too — narrowly, so an app whose compose sets a real env var named after itself is untouched. - Tools/hooks kept uppercase CFG_<TYPE>_ reads, so an instance provisioned itself from the type's config and ignored its own values. - Cloned hooks were never loaded: both loaders run at startup, before the instance dir exists, so _appCallHook's `declare -F` found nothing and every <slug>_install_* hook silently no-opped — for bookstack that is the readiness probe and the admin bootstrap. Source the instance's own scripts in-process, then regen arrays + manifest for later runs. - bookstack's hook hardcoded the container name after `docker exec -e ...` flags, where the rewriter can't see it, so an instance's admin bootstrap ran against the BASE app's container — including a tinker DELETE of a user. Target "$app_name" instead, and teach the rewriter the container="<type>" assignment form used by auth adapters. network_resources uniqueness: UNIQUE(resource_type, resource_value) is right for 'ip' and 'port' but the port-tag writer stores descriptive rows in the same table with INSERT OR REPLACE, so every install DELETED the matching row from whichever app held it. traefik_managed and url_accessible are booleans, so the whole table could only ever hold one row of each. Observed live: installing a second bookstack took all four traefik_managed/url_accessible rows from stoat and bookstack, and removing that instance took the stolen rows with it. Replace it with a partial unique index scoped to ip/port, and migrate existing databases in place (SQLite can't drop a constraint, so the table is rebuilt inside a transaction). The migration is invoked from portUpdateComposeTags, not just databaseCreateTables — the latter only runs from startPreInstall, which a working install never re-runs. Verified: two bookstacks now hold port_tag_internal=80, traefik_managed and url_accessible simultaneously; duplicate host ports and IPs are still rejected; instance installs, serves HTTP 200, provisions its own admin in its own database, and removes cleanly with no orphan rows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f9ec4cc986
commit
ff25b08ee8
@ -46,17 +46,23 @@ bookstack_install_post_start()
|
|||||||
fi
|
fi
|
||||||
isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})."
|
isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})."
|
||||||
|
|
||||||
|
# Target the container by $app_name, never the literal "bookstack": under
|
||||||
|
# multi-instance this hook is cloned for each instance, and a hardcoded name
|
||||||
|
# pointed every instance's admin bootstrap at the BASE app's container —
|
||||||
|
# provisioning (and, in the branch below, DELETING) users in the wrong
|
||||||
|
# database. instanceCreate's rewriter can't catch it either, since the
|
||||||
|
# container name here doesn't directly follow `docker exec`.
|
||||||
local bookstack_create_output
|
local bookstack_create_output
|
||||||
bookstack_create_output=$(runFileOp docker exec \
|
bookstack_create_output=$(runFileOp docker exec \
|
||||||
-e EZ_BS_NEW_EMAIL="$bookstack_target_email" \
|
-e EZ_BS_NEW_EMAIL="$bookstack_target_email" \
|
||||||
-e EZ_BS_NEW_PASS="$bookstack_target_pass" \
|
-e EZ_BS_NEW_PASS="$bookstack_target_pass" \
|
||||||
bookstack sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1')
|
"$app_name" sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1')
|
||||||
local bookstack_create_rc=$?
|
local bookstack_create_rc=$?
|
||||||
if [[ $bookstack_create_rc -eq 0 ]]; then
|
if [[ $bookstack_create_rc -eq 0 ]]; then
|
||||||
isSuccessful "Bookstack admin account created (email: $bookstack_target_email)."
|
isSuccessful "Bookstack admin account created (email: $bookstack_target_email)."
|
||||||
|
|
||||||
if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then
|
if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then
|
||||||
runFileOp docker exec -i bookstack php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP'
|
runFileOp docker exec -i "$app_name" php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP'
|
||||||
$c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User';
|
$c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User';
|
||||||
optional($c::where('email', 'admin@admin.com')->first())->delete();
|
optional($c::where('email', 'admin@admin.com')->first())->delete();
|
||||||
PHP
|
PHP
|
||||||
|
|||||||
@ -104,8 +104,7 @@ databaseCreateTables()
|
|||||||
status TEXT DEFAULT 'active',
|
status TEXT DEFAULT 'active',
|
||||||
created_date DATE DEFAULT CURRENT_DATE,
|
created_date DATE DEFAULT CURRENT_DATE,
|
||||||
created_time TIME DEFAULT CURRENT_TIME,
|
created_time TIME DEFAULT CURRENT_TIME,
|
||||||
UNIQUE(app_name, resource_type, service_name),
|
UNIQUE(app_name, resource_type, service_name)
|
||||||
UNIQUE(resource_type, resource_value)
|
|
||||||
);")
|
);")
|
||||||
checkSuccess "Creating unified network_resources table"
|
checkSuccess "Creating unified network_resources table"
|
||||||
|
|
||||||
@ -121,7 +120,81 @@ databaseCreateTables()
|
|||||||
local result; result=$(sqlite3 "$docker_dir/$db_file" "CREATE INDEX IF NOT EXISTS idx_network_resources_parent_service ON network_resources(parent_service);")
|
local result; result=$(sqlite3 "$docker_dir/$db_file" "CREATE INDEX IF NOT EXISTS idx_network_resources_parent_service ON network_resources(parent_service);")
|
||||||
checkSuccess "Creating network resources parent service index"
|
checkSuccess "Creating network resources parent service index"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Runs for fresh AND existing databases (this function is re-run on every
|
||||||
|
# startup), so an install created before the constraint was scoped is
|
||||||
|
# repaired in place.
|
||||||
|
databaseMigrateNetworkResourcesUnique
|
||||||
else
|
else
|
||||||
echo "SQLite3 is not installed. Skipping table creation."
|
echo "SQLite3 is not installed. Skipping table creation."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Scope the global-uniqueness constraint on network_resources to the resources
|
||||||
|
# that are actually globally unique.
|
||||||
|
#
|
||||||
|
# The table shipped with UNIQUE(resource_type, resource_value). That is right for
|
||||||
|
# 'ip' and 'port' — no two apps may hold the same host port or container IP — but
|
||||||
|
# the port-tag writer stores descriptive rows in the same table and writes them
|
||||||
|
# with INSERT OR REPLACE, so each install DELETED the matching row from whichever
|
||||||
|
# app held it:
|
||||||
|
# port_tag_internal the CONTAINER-side port: every web app uses 80
|
||||||
|
# traefik_managed 'true'/'false' — two possible values, so the whole table
|
||||||
|
# url_accessible could only ever hold ONE row of each, for one app
|
||||||
|
# Consequences: the firewall rebuild's traefik_managed LEFT JOIN reads NULL for
|
||||||
|
# every app but the last one installed, and in rooted mode a stolen
|
||||||
|
# port_tag_internal makes ufw-docker fall back to the EXTERNAL port — the exact
|
||||||
|
# "cannot find the published port" failure firewall_rebuild_from_db.sh warns
|
||||||
|
# about. Rows already lost are not reconstructable here; each app repopulates its
|
||||||
|
# own on the next `libreportal app install <app>`.
|
||||||
|
#
|
||||||
|
# SQLite cannot drop a table constraint, so this rebuilds the table when the
|
||||||
|
# legacy constraint is still present, then enforces the narrow rule as a partial
|
||||||
|
# unique index. Idempotent: once migrated, the guard skips it.
|
||||||
|
databaseMigrateNetworkResourcesUnique()
|
||||||
|
{
|
||||||
|
local table_sql
|
||||||
|
table_sql=$(sqlite3 "$docker_dir/$db_file" "SELECT sql FROM sqlite_master WHERE type='table' AND name='network_resources';" 2>/dev/null)
|
||||||
|
[[ -n "$table_sql" ]] || return 0
|
||||||
|
|
||||||
|
if [[ "$table_sql" == *"UNIQUE(resource_type, resource_value)"* ]]; then
|
||||||
|
# Single transaction: either the whole swap lands or the old table stays.
|
||||||
|
local result; result=$(sqlite3 "$docker_dir/$db_file" "
|
||||||
|
PRAGMA foreign_keys=off;
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
CREATE TABLE network_resources_migrated (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
app_name TEXT NOT NULL,
|
||||||
|
resource_type TEXT NOT NULL,
|
||||||
|
resource_value TEXT NOT NULL,
|
||||||
|
service_name TEXT DEFAULT 'main',
|
||||||
|
parent_service TEXT DEFAULT NULL,
|
||||||
|
status TEXT DEFAULT 'active',
|
||||||
|
created_date DATE DEFAULT CURRENT_DATE,
|
||||||
|
created_time TIME DEFAULT CURRENT_TIME,
|
||||||
|
UNIQUE(app_name, resource_type, service_name)
|
||||||
|
);
|
||||||
|
INSERT INTO network_resources_migrated
|
||||||
|
SELECT id, app_name, resource_type, resource_value, service_name,
|
||||||
|
parent_service, status, created_date, created_time
|
||||||
|
FROM network_resources;
|
||||||
|
DROP TABLE network_resources;
|
||||||
|
ALTER TABLE network_resources_migrated RENAME TO network_resources;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_network_resources_app ON network_resources(app_name);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_network_resources_type ON network_resources(resource_type);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_network_resources_value ON network_resources(resource_value);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_network_resources_status ON network_resources(status);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_network_resources_parent_service ON network_resources(parent_service);
|
||||||
|
COMMIT;
|
||||||
|
" 2>&1)
|
||||||
|
if [[ -n "$result" ]]; then
|
||||||
|
isNotice "network_resources migration reported: $result"
|
||||||
|
fi
|
||||||
|
checkSuccess "Scoping network_resources uniqueness to ip/port"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The narrow rule, as a partial index — still blocks two apps claiming the
|
||||||
|
# same host port or IP, and lets the descriptive rows coexist. Silent: it is
|
||||||
|
# a no-op on every startup after the first.
|
||||||
|
local result; result=$(sqlite3 "$docker_dir/$db_file" "CREATE UNIQUE INDEX IF NOT EXISTS idx_network_resources_global_value ON network_resources(resource_type, resource_value) WHERE resource_type IN ('ip','port');" 2>/dev/null)
|
||||||
|
}
|
||||||
|
|||||||
@ -94,6 +94,19 @@ _instanceRewriteCompose() {
|
|||||||
sed -i -E "s/(container_name:[[:space:]]*)${type}\b/\1${slug}/g" "$f"
|
sed -i -E "s/(container_name:[[:space:]]*)${type}\b/\1${slug}/g" "$f"
|
||||||
# 3. The files-backup label's container ref (libreportal.backup.files: "<type>:/...").
|
# 3. The files-backup label's container ref (libreportal.backup.files: "<type>:/...").
|
||||||
sed -i -E "s/(libreportal\.backup\.files:[[:space:]]*\")${type}\b/\1${slug}/g" "$f"
|
sed -i -E "s/(libreportal\.backup\.files:[[:space:]]*\")${type}\b/\1${slug}/g" "$f"
|
||||||
|
# 4. The per-app tag namespace. tagsProcessorAppConfigValues derives tag names
|
||||||
|
# mechanically from the config keys (CFG_<APP>_APP_KEY_1 -> the tag
|
||||||
|
# <APP>_APP_KEY_1_TAG), so a clone still carrying the TYPE's tag names has
|
||||||
|
# nothing to match its own CFG_<SLUG>_* vars: the placeholders survive and
|
||||||
|
# the pre-start guard refuses to launch the instance.
|
||||||
|
# Deliberately narrow — the tag name right after the #LIBREPORTAL| marker,
|
||||||
|
# and the *_DATA placeholder tokens. A blanket <TYPE>_ rewrite would also
|
||||||
|
# hit an app whose compose sets a real container env var named after itself
|
||||||
|
# (- <TYPE>_SECRET=...), renaming the variable the image reads.
|
||||||
|
local type_u="${type^^}" slug_u="${slug^^}"
|
||||||
|
type_u="${type_u//-/_}"; slug_u="${slug_u//-/_}"
|
||||||
|
sed -i -E "s/(#LIBREPORTAL\|)${type_u}_/\1${slug_u}_/g" "$f"
|
||||||
|
sed -i -E "s/\b${type_u}_([A-Z0-9_]*)_DATA\b/${slug_u}_\1_DATA/g" "$f"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Clone + prefix-rename the per-app tools/scripts so an instance's helpers target
|
# Clone + prefix-rename the per-app tools/scripts so an instance's helpers target
|
||||||
@ -117,6 +130,17 @@ _instanceRewriteTools() {
|
|||||||
sed -i -E "s/\b${type}_/${slug}_/g" "$f"
|
sed -i -E "s/\b${type}_/${slug}_/g" "$f"
|
||||||
sed -i -E "s/(docker[[:space:]]+(exec|logs|restart|stop|start|inspect)[[:space:]]+)${type}\b/\1${slug}/g" "$f"
|
sed -i -E "s/(docker[[:space:]]+(exec|logs|restart|stop|start|inspect)[[:space:]]+)${type}\b/\1${slug}/g" "$f"
|
||||||
sed -i -E "s/\b${type}\.config\b/${slug}.config/g" "$f"
|
sed -i -E "s/\b${type}\.config\b/${slug}.config/g" "$f"
|
||||||
|
# Config reads are uppercase and so escape the lowercase rename above:
|
||||||
|
# an instance hook left reading CFG_<TYPE>_ADMIN_EMAIL would provision
|
||||||
|
# itself from the type's config (its own value silently ignored).
|
||||||
|
sed -i -E "s/\bCFG_${type^^}_/CFG_${slug^^}_/g" "$f"
|
||||||
|
# container="<type>" / container_name="<type>" holds the docker target
|
||||||
|
# for exec-based helpers (auth adapters, tools). The bare literal has
|
||||||
|
# no trailing underscore, so the rename above misses it and the clone
|
||||||
|
# would operate on the BASE app's container. Kept to these two
|
||||||
|
# assignment forms — a blanket bare-<type> rewrite would hit image
|
||||||
|
# names and prose.
|
||||||
|
sed -i -E "s/(\b(container|container_name)=\")${type}(\")/\1${slug}\3/g" "$f"
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@ -202,7 +226,27 @@ instanceCreate() {
|
|||||||
|
|
||||||
isSuccessful "Instance template ready: $slug (instance of $type)"
|
isSuccessful "Instance template ready: $slug (instance of $type)"
|
||||||
|
|
||||||
# 5. Hand off to the standard installer — from here it's just another app.
|
# 5. Make the instance's freshly-cloned installers/hooks callable in THIS
|
||||||
|
# process. Both loaders ran at startup, before this dir existed: the eager
|
||||||
|
# scan (sourceScanFiles "containers") never saw it, and the lazy manifest
|
||||||
|
# has no stub for it. Without this, _appCallHook's `declare -F` finds
|
||||||
|
# nothing and every <slug>_install_* hook silently no-ops — for bookstack
|
||||||
|
# that is the readiness probe and the admin-account bootstrap, so the
|
||||||
|
# instance installs "successfully" with no usable login.
|
||||||
|
local _inst_f
|
||||||
|
while IFS= read -r -d '' _inst_f; do
|
||||||
|
source "$_inst_f"
|
||||||
|
done < <(find "$inst_dir" -maxdepth 2 -type d -name resources -prune -o -type f -name '*.sh' -print0 2>/dev/null)
|
||||||
|
|
||||||
|
# Persist that for later runs (and the WebUI): regenerate the file arrays +
|
||||||
|
# function manifest now that a new app dir exists. Best-effort — a stale
|
||||||
|
# manifest only affects lazy mode, and the in-process sourcing above already
|
||||||
|
# covers this install.
|
||||||
|
if declare -F lpRegenArrays >/dev/null 2>&1; then
|
||||||
|
lpRegenArrays force >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. Hand off to the standard installer — from here it's just another app.
|
||||||
if ! declare -F dockerInstallApp >/dev/null 2>&1; then
|
if ! declare -F dockerInstallApp >/dev/null 2>&1; then
|
||||||
isError "dockerInstallApp unavailable; instance template created but not installed."
|
isError "dockerInstallApp unavailable; instance template created but not installed."
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@ -5,7 +5,18 @@ portUpdateComposeTags()
|
|||||||
{
|
{
|
||||||
local app_name="$1"
|
local app_name="$1"
|
||||||
local full_file_path="$2"
|
local full_file_path="$2"
|
||||||
|
|
||||||
|
# This function is the only INSERT OR REPLACE writer into network_resources,
|
||||||
|
# so it is where the legacy UNIQUE(resource_type, resource_value) did its
|
||||||
|
# damage — each run silently stole other apps' port_tag_internal /
|
||||||
|
# traefik_managed / url_accessible rows. Repair the constraint here rather
|
||||||
|
# than only in databaseCreateTables: that runs from startPreInstall, which a
|
||||||
|
# working install never re-runs, so existing installs would keep corrupting
|
||||||
|
# themselves until a full reinstall. One guarded SELECT; a no-op once done.
|
||||||
|
if declare -F databaseMigrateNetworkResourcesUnique >/dev/null 2>&1; then
|
||||||
|
databaseMigrateNetworkResourcesUnique
|
||||||
|
fi
|
||||||
|
|
||||||
local port_tags_found=()
|
local port_tags_found=()
|
||||||
local port_numbers=()
|
local port_numbers=()
|
||||||
|
|
||||||
|
|||||||
@ -58,12 +58,12 @@ declare -gA LP_FN_MAP=(
|
|||||||
[appLinkdingResetPassword]="linkding/tools/linkding_reset_password.sh"
|
[appLinkdingResetPassword]="linkding/tools/linkding_reset_password.sh"
|
||||||
[appLinkdingSetAdmin]="linkding/tools/linkding_set_admin.sh"
|
[appLinkdingSetAdmin]="linkding/tools/linkding_set_admin.sh"
|
||||||
[appMatrixCreateAccount]="matrix/tools/matrix_create_account.sh"
|
[appMatrixCreateAccount]="matrix/tools/matrix_create_account.sh"
|
||||||
[appMatrixDeactivateUser]="matrix/tools/matrix_deactivate_user.sh"
|
[appMatrixDeleteUser]="matrix/tools/matrix_delete_user.sh"
|
||||||
[appMatrixListUsers]="matrix/tools/matrix_list_users.sh"
|
[appMatrixListUsers]="matrix/tools/matrix_list_users.sh"
|
||||||
[appMatrixResetPassword]="matrix/tools/matrix_reset_password.sh"
|
[appMatrixResetPassword]="matrix/tools/matrix_reset_password.sh"
|
||||||
[appMatrixSetAdmin]="matrix/tools/matrix_set_admin.sh"
|
[appMatrixSetAdmin]="matrix/tools/matrix_set_admin.sh"
|
||||||
[appMattermostCreateAccount]="mattermost/tools/mattermost_create_account.sh"
|
[appMattermostCreateAccount]="mattermost/tools/mattermost_create_account.sh"
|
||||||
[appMattermostDeactivateUser]="mattermost/tools/mattermost_deactivate_user.sh"
|
[appMattermostDeleteUser]="mattermost/tools/mattermost_delete_user.sh"
|
||||||
[appMattermostListUsers]="mattermost/tools/mattermost_list_users.sh"
|
[appMattermostListUsers]="mattermost/tools/mattermost_list_users.sh"
|
||||||
[appMattermostResetPassword]="mattermost/tools/mattermost_reset_password.sh"
|
[appMattermostResetPassword]="mattermost/tools/mattermost_reset_password.sh"
|
||||||
[appMattermostSetAdmin]="mattermost/tools/mattermost_set_admin.sh"
|
[appMattermostSetAdmin]="mattermost/tools/mattermost_set_admin.sh"
|
||||||
@ -86,7 +86,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[_appReqServiceInstalled]="checks/requirements/check_app_install.sh"
|
[_appReqServiceInstalled]="checks/requirements/check_app_install.sh"
|
||||||
[_appReqServiceMsg]="checks/requirements/check_app_install.sh"
|
[_appReqServiceMsg]="checks/requirements/check_app_install.sh"
|
||||||
[appRocketchatCreateAccount]="rocketchat/tools/rocketchat_create_account.sh"
|
[appRocketchatCreateAccount]="rocketchat/tools/rocketchat_create_account.sh"
|
||||||
[appRocketchatDeactivateUser]="rocketchat/tools/rocketchat_deactivate_user.sh"
|
[appRocketchatDeleteUser]="rocketchat/tools/rocketchat_delete_user.sh"
|
||||||
[appRocketchatEnableUser]="rocketchat/tools/rocketchat_enable_user.sh"
|
[appRocketchatEnableUser]="rocketchat/tools/rocketchat_enable_user.sh"
|
||||||
[appRocketchatListUsers]="rocketchat/tools/rocketchat_list_users.sh"
|
[appRocketchatListUsers]="rocketchat/tools/rocketchat_list_users.sh"
|
||||||
[appRocketchatResetPassword]="rocketchat/tools/rocketchat_reset_password.sh"
|
[appRocketchatResetPassword]="rocketchat/tools/rocketchat_reset_password.sh"
|
||||||
@ -103,7 +103,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[appStalwartSetMode]="stalwart/tools/stalwart_set_mode.sh"
|
[appStalwartSetMode]="stalwart/tools/stalwart_set_mode.sh"
|
||||||
[appStalwartShowDns]="stalwart/tools/stalwart_show_dns.sh"
|
[appStalwartShowDns]="stalwart/tools/stalwart_show_dns.sh"
|
||||||
[appStatus]="app/app_status.sh"
|
[appStatus]="app/app_status.sh"
|
||||||
[appStoatDisableUser]="stoat/tools/stoat_disable_user.sh"
|
[appStoatDeleteUser]="stoat/tools/stoat_delete_user.sh"
|
||||||
[appStoatEnableUser]="stoat/tools/stoat_enable_user.sh"
|
[appStoatEnableUser]="stoat/tools/stoat_enable_user.sh"
|
||||||
[appStoatListUsers]="stoat/tools/stoat_list_users.sh"
|
[appStoatListUsers]="stoat/tools/stoat_list_users.sh"
|
||||||
[appTraefikExtraMiddlewares_onlyoffice]="onlyoffice/scripts/onlyoffice_traefik.sh"
|
[appTraefikExtraMiddlewares_onlyoffice]="onlyoffice/scripts/onlyoffice_traefik.sh"
|
||||||
@ -405,6 +405,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[databaseListAllApps]="database/app/db_list_all_apps.sh"
|
[databaseListAllApps]="database/app/db_list_all_apps.sh"
|
||||||
[databaseListInstalledApp]="database/app/db_list_installed_app.sh"
|
[databaseListInstalledApp]="database/app/db_list_installed_app.sh"
|
||||||
[databaseListInstalledApps]="database/app/db_list_installed_apps.sh"
|
[databaseListInstalledApps]="database/app/db_list_installed_apps.sh"
|
||||||
|
[databaseMigrateNetworkResourcesUnique]="database/tables/db_create_tables.sh"
|
||||||
[databaseOptionInsert]="database/insert/db_insert_option.sh"
|
[databaseOptionInsert]="database/insert/db_insert_option.sh"
|
||||||
[databasePortOpenInsert]="database/insert/db_insert_port_open.sh"
|
[databasePortOpenInsert]="database/insert/db_insert_port_open.sh"
|
||||||
[databasePortUsedInsert]="database/insert/db_insert_port_used.sh"
|
[databasePortUsedInsert]="database/insert/db_insert_port_used.sh"
|
||||||
@ -1181,12 +1182,12 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[appLinkdingResetPassword]="containers"
|
[appLinkdingResetPassword]="containers"
|
||||||
[appLinkdingSetAdmin]="containers"
|
[appLinkdingSetAdmin]="containers"
|
||||||
[appMatrixCreateAccount]="containers"
|
[appMatrixCreateAccount]="containers"
|
||||||
[appMatrixDeactivateUser]="containers"
|
[appMatrixDeleteUser]="containers"
|
||||||
[appMatrixListUsers]="containers"
|
[appMatrixListUsers]="containers"
|
||||||
[appMatrixResetPassword]="containers"
|
[appMatrixResetPassword]="containers"
|
||||||
[appMatrixSetAdmin]="containers"
|
[appMatrixSetAdmin]="containers"
|
||||||
[appMattermostCreateAccount]="containers"
|
[appMattermostCreateAccount]="containers"
|
||||||
[appMattermostDeactivateUser]="containers"
|
[appMattermostDeleteUser]="containers"
|
||||||
[appMattermostListUsers]="containers"
|
[appMattermostListUsers]="containers"
|
||||||
[appMattermostResetPassword]="containers"
|
[appMattermostResetPassword]="containers"
|
||||||
[appMattermostSetAdmin]="containers"
|
[appMattermostSetAdmin]="containers"
|
||||||
@ -1209,7 +1210,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[_appReqServiceInstalled]="scripts"
|
[_appReqServiceInstalled]="scripts"
|
||||||
[_appReqServiceMsg]="scripts"
|
[_appReqServiceMsg]="scripts"
|
||||||
[appRocketchatCreateAccount]="containers"
|
[appRocketchatCreateAccount]="containers"
|
||||||
[appRocketchatDeactivateUser]="containers"
|
[appRocketchatDeleteUser]="containers"
|
||||||
[appRocketchatEnableUser]="containers"
|
[appRocketchatEnableUser]="containers"
|
||||||
[appRocketchatListUsers]="containers"
|
[appRocketchatListUsers]="containers"
|
||||||
[appRocketchatResetPassword]="containers"
|
[appRocketchatResetPassword]="containers"
|
||||||
@ -1226,7 +1227,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[appStalwartSetMode]="containers"
|
[appStalwartSetMode]="containers"
|
||||||
[appStalwartShowDns]="containers"
|
[appStalwartShowDns]="containers"
|
||||||
[appStatus]="scripts"
|
[appStatus]="scripts"
|
||||||
[appStoatDisableUser]="containers"
|
[appStoatDeleteUser]="containers"
|
||||||
[appStoatEnableUser]="containers"
|
[appStoatEnableUser]="containers"
|
||||||
[appStoatListUsers]="containers"
|
[appStoatListUsers]="containers"
|
||||||
[appTraefikExtraMiddlewares_onlyoffice]="containers"
|
[appTraefikExtraMiddlewares_onlyoffice]="containers"
|
||||||
@ -1528,6 +1529,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[databaseListAllApps]="scripts"
|
[databaseListAllApps]="scripts"
|
||||||
[databaseListInstalledApp]="scripts"
|
[databaseListInstalledApp]="scripts"
|
||||||
[databaseListInstalledApps]="scripts"
|
[databaseListInstalledApps]="scripts"
|
||||||
|
[databaseMigrateNetworkResourcesUnique]="scripts"
|
||||||
[databaseOptionInsert]="scripts"
|
[databaseOptionInsert]="scripts"
|
||||||
[databasePortOpenInsert]="scripts"
|
[databasePortOpenInsert]="scripts"
|
||||||
[databasePortUsedInsert]="scripts"
|
[databasePortUsedInsert]="scripts"
|
||||||
@ -2339,12 +2341,12 @@ appLinkdingListUsers() { unset -f appLinkdingListUsers; __lpAutoload "${install_
|
|||||||
appLinkdingResetPassword() { unset -f appLinkdingResetPassword; __lpAutoload "${install_containers_dir}linkding/tools/linkding_reset_password.sh"; appLinkdingResetPassword "$@"; }
|
appLinkdingResetPassword() { unset -f appLinkdingResetPassword; __lpAutoload "${install_containers_dir}linkding/tools/linkding_reset_password.sh"; appLinkdingResetPassword "$@"; }
|
||||||
appLinkdingSetAdmin() { unset -f appLinkdingSetAdmin; __lpAutoload "${install_containers_dir}linkding/tools/linkding_set_admin.sh"; appLinkdingSetAdmin "$@"; }
|
appLinkdingSetAdmin() { unset -f appLinkdingSetAdmin; __lpAutoload "${install_containers_dir}linkding/tools/linkding_set_admin.sh"; appLinkdingSetAdmin "$@"; }
|
||||||
appMatrixCreateAccount() { unset -f appMatrixCreateAccount; __lpAutoload "${install_containers_dir}matrix/tools/matrix_create_account.sh"; appMatrixCreateAccount "$@"; }
|
appMatrixCreateAccount() { unset -f appMatrixCreateAccount; __lpAutoload "${install_containers_dir}matrix/tools/matrix_create_account.sh"; appMatrixCreateAccount "$@"; }
|
||||||
appMatrixDeactivateUser() { unset -f appMatrixDeactivateUser; __lpAutoload "${install_containers_dir}matrix/tools/matrix_deactivate_user.sh"; appMatrixDeactivateUser "$@"; }
|
appMatrixDeleteUser() { unset -f appMatrixDeleteUser; __lpAutoload "${install_containers_dir}matrix/tools/matrix_delete_user.sh"; appMatrixDeleteUser "$@"; }
|
||||||
appMatrixListUsers() { unset -f appMatrixListUsers; __lpAutoload "${install_containers_dir}matrix/tools/matrix_list_users.sh"; appMatrixListUsers "$@"; }
|
appMatrixListUsers() { unset -f appMatrixListUsers; __lpAutoload "${install_containers_dir}matrix/tools/matrix_list_users.sh"; appMatrixListUsers "$@"; }
|
||||||
appMatrixResetPassword() { unset -f appMatrixResetPassword; __lpAutoload "${install_containers_dir}matrix/tools/matrix_reset_password.sh"; appMatrixResetPassword "$@"; }
|
appMatrixResetPassword() { unset -f appMatrixResetPassword; __lpAutoload "${install_containers_dir}matrix/tools/matrix_reset_password.sh"; appMatrixResetPassword "$@"; }
|
||||||
appMatrixSetAdmin() { unset -f appMatrixSetAdmin; __lpAutoload "${install_containers_dir}matrix/tools/matrix_set_admin.sh"; appMatrixSetAdmin "$@"; }
|
appMatrixSetAdmin() { unset -f appMatrixSetAdmin; __lpAutoload "${install_containers_dir}matrix/tools/matrix_set_admin.sh"; appMatrixSetAdmin "$@"; }
|
||||||
appMattermostCreateAccount() { unset -f appMattermostCreateAccount; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_create_account.sh"; appMattermostCreateAccount "$@"; }
|
appMattermostCreateAccount() { unset -f appMattermostCreateAccount; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_create_account.sh"; appMattermostCreateAccount "$@"; }
|
||||||
appMattermostDeactivateUser() { unset -f appMattermostDeactivateUser; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_deactivate_user.sh"; appMattermostDeactivateUser "$@"; }
|
appMattermostDeleteUser() { unset -f appMattermostDeleteUser; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_delete_user.sh"; appMattermostDeleteUser "$@"; }
|
||||||
appMattermostListUsers() { unset -f appMattermostListUsers; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_list_users.sh"; appMattermostListUsers "$@"; }
|
appMattermostListUsers() { unset -f appMattermostListUsers; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_list_users.sh"; appMattermostListUsers "$@"; }
|
||||||
appMattermostResetPassword() { unset -f appMattermostResetPassword; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_reset_password.sh"; appMattermostResetPassword "$@"; }
|
appMattermostResetPassword() { unset -f appMattermostResetPassword; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_reset_password.sh"; appMattermostResetPassword "$@"; }
|
||||||
appMattermostSetAdmin() { unset -f appMattermostSetAdmin; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_set_admin.sh"; appMattermostSetAdmin "$@"; }
|
appMattermostSetAdmin() { unset -f appMattermostSetAdmin; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_set_admin.sh"; appMattermostSetAdmin "$@"; }
|
||||||
@ -2367,7 +2369,7 @@ _appReqHasDomain() { unset -f _appReqHasDomain; __lpAutoload "${install_scripts_
|
|||||||
_appReqServiceInstalled() { unset -f _appReqServiceInstalled; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceInstalled "$@"; }
|
_appReqServiceInstalled() { unset -f _appReqServiceInstalled; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceInstalled "$@"; }
|
||||||
_appReqServiceMsg() { unset -f _appReqServiceMsg; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceMsg "$@"; }
|
_appReqServiceMsg() { unset -f _appReqServiceMsg; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceMsg "$@"; }
|
||||||
appRocketchatCreateAccount() { unset -f appRocketchatCreateAccount; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_create_account.sh"; appRocketchatCreateAccount "$@"; }
|
appRocketchatCreateAccount() { unset -f appRocketchatCreateAccount; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_create_account.sh"; appRocketchatCreateAccount "$@"; }
|
||||||
appRocketchatDeactivateUser() { unset -f appRocketchatDeactivateUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_deactivate_user.sh"; appRocketchatDeactivateUser "$@"; }
|
appRocketchatDeleteUser() { unset -f appRocketchatDeleteUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_delete_user.sh"; appRocketchatDeleteUser "$@"; }
|
||||||
appRocketchatEnableUser() { unset -f appRocketchatEnableUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_enable_user.sh"; appRocketchatEnableUser "$@"; }
|
appRocketchatEnableUser() { unset -f appRocketchatEnableUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_enable_user.sh"; appRocketchatEnableUser "$@"; }
|
||||||
appRocketchatListUsers() { unset -f appRocketchatListUsers; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_list_users.sh"; appRocketchatListUsers "$@"; }
|
appRocketchatListUsers() { unset -f appRocketchatListUsers; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_list_users.sh"; appRocketchatListUsers "$@"; }
|
||||||
appRocketchatResetPassword() { unset -f appRocketchatResetPassword; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_reset_password.sh"; appRocketchatResetPassword "$@"; }
|
appRocketchatResetPassword() { unset -f appRocketchatResetPassword; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_reset_password.sh"; appRocketchatResetPassword "$@"; }
|
||||||
@ -2384,7 +2386,7 @@ appSetupComposeTags_wireguard() { unset -f appSetupComposeTags_wireguard; __lpAu
|
|||||||
appStalwartSetMode() { unset -f appStalwartSetMode; __lpAutoload "${install_containers_dir}stalwart/tools/stalwart_set_mode.sh"; appStalwartSetMode "$@"; }
|
appStalwartSetMode() { unset -f appStalwartSetMode; __lpAutoload "${install_containers_dir}stalwart/tools/stalwart_set_mode.sh"; appStalwartSetMode "$@"; }
|
||||||
appStalwartShowDns() { unset -f appStalwartShowDns; __lpAutoload "${install_containers_dir}stalwart/tools/stalwart_show_dns.sh"; appStalwartShowDns "$@"; }
|
appStalwartShowDns() { unset -f appStalwartShowDns; __lpAutoload "${install_containers_dir}stalwart/tools/stalwart_show_dns.sh"; appStalwartShowDns "$@"; }
|
||||||
appStatus() { unset -f appStatus; __lpAutoload "${install_scripts_dir}app/app_status.sh"; appStatus "$@"; }
|
appStatus() { unset -f appStatus; __lpAutoload "${install_scripts_dir}app/app_status.sh"; appStatus "$@"; }
|
||||||
appStoatDisableUser() { unset -f appStoatDisableUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_disable_user.sh"; appStoatDisableUser "$@"; }
|
appStoatDeleteUser() { unset -f appStoatDeleteUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_delete_user.sh"; appStoatDeleteUser "$@"; }
|
||||||
appStoatEnableUser() { unset -f appStoatEnableUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_enable_user.sh"; appStoatEnableUser "$@"; }
|
appStoatEnableUser() { unset -f appStoatEnableUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_enable_user.sh"; appStoatEnableUser "$@"; }
|
||||||
appStoatListUsers() { unset -f appStoatListUsers; __lpAutoload "${install_containers_dir}stoat/tools/stoat_list_users.sh"; appStoatListUsers "$@"; }
|
appStoatListUsers() { unset -f appStoatListUsers; __lpAutoload "${install_containers_dir}stoat/tools/stoat_list_users.sh"; appStoatListUsers "$@"; }
|
||||||
appTraefikExtraMiddlewares_onlyoffice() { unset -f appTraefikExtraMiddlewares_onlyoffice; __lpAutoload "${install_containers_dir}onlyoffice/scripts/onlyoffice_traefik.sh"; appTraefikExtraMiddlewares_onlyoffice "$@"; }
|
appTraefikExtraMiddlewares_onlyoffice() { unset -f appTraefikExtraMiddlewares_onlyoffice; __lpAutoload "${install_containers_dir}onlyoffice/scripts/onlyoffice_traefik.sh"; appTraefikExtraMiddlewares_onlyoffice "$@"; }
|
||||||
@ -2686,6 +2688,7 @@ databaseInstallApp() { unset -f databaseInstallApp; __lpAutoload "${install_scri
|
|||||||
databaseListAllApps() { unset -f databaseListAllApps; __lpAutoload "${install_scripts_dir}database/app/db_list_all_apps.sh"; databaseListAllApps "$@"; }
|
databaseListAllApps() { unset -f databaseListAllApps; __lpAutoload "${install_scripts_dir}database/app/db_list_all_apps.sh"; databaseListAllApps "$@"; }
|
||||||
databaseListInstalledApp() { unset -f databaseListInstalledApp; __lpAutoload "${install_scripts_dir}database/app/db_list_installed_app.sh"; databaseListInstalledApp "$@"; }
|
databaseListInstalledApp() { unset -f databaseListInstalledApp; __lpAutoload "${install_scripts_dir}database/app/db_list_installed_app.sh"; databaseListInstalledApp "$@"; }
|
||||||
databaseListInstalledApps() { unset -f databaseListInstalledApps; __lpAutoload "${install_scripts_dir}database/app/db_list_installed_apps.sh"; databaseListInstalledApps "$@"; }
|
databaseListInstalledApps() { unset -f databaseListInstalledApps; __lpAutoload "${install_scripts_dir}database/app/db_list_installed_apps.sh"; databaseListInstalledApps "$@"; }
|
||||||
|
databaseMigrateNetworkResourcesUnique() { unset -f databaseMigrateNetworkResourcesUnique; __lpAutoload "${install_scripts_dir}database/tables/db_create_tables.sh"; databaseMigrateNetworkResourcesUnique "$@"; }
|
||||||
databaseOptionInsert() { unset -f databaseOptionInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_option.sh"; databaseOptionInsert "$@"; }
|
databaseOptionInsert() { unset -f databaseOptionInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_option.sh"; databaseOptionInsert "$@"; }
|
||||||
databasePortOpenInsert() { unset -f databasePortOpenInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_port_open.sh"; databasePortOpenInsert "$@"; }
|
databasePortOpenInsert() { unset -f databasePortOpenInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_port_open.sh"; databasePortOpenInsert "$@"; }
|
||||||
databasePortUsedInsert() { unset -f databasePortUsedInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_port_used.sh"; databasePortUsedInsert "$@"; }
|
databasePortUsedInsert() { unset -f databasePortUsedInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_port_used.sh"; databasePortUsedInsert "$@"; }
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user