Files
ProxmoxVE/ct/pangolin.sh
CanbiZ (MickLesk) 3ac2ceda3d fix(pangolin): create migration tables before data transfer to prevent role loss (#13874)
The previous migration fix attempted to INSERT INTO 'userOrgRoles' before
that table existed (it is new in 1.17.1). The error was silently ignored,
so no role data was migrated. When drizzle-kit then dropped roleId from
userOrgs, all user-role associations were permanently lost.

- CREATE TABLE IF NOT EXISTS for userOrgRoles before migrating data
- Same treatment for userInviteRoles (also new in 1.17.1)

Fixes community-scripts/ProxmoxVE#13857
2026-04-20 13:23:32 +02:00

123 lines
4.6 KiB
Bash

#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://pangolin.net/ | Github: https://github.com/fosrl/pangolin
APP="Pangolin"
var_tags="${var_tags:-proxy}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
var_tun="${var_tun:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/pangolin ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
ensure_dependencies build-essential python3
NODE_VERSION="24" setup_nodejs
if check_for_gh_release "pangolin" "fosrl/pangolin"; then
msg_info "Stopping Service"
systemctl stop pangolin
systemctl stop gerbil
msg_info "Service stopped"
msg_info "Creating backup"
tar -czf /opt/pangolin_config_backup.tar.gz -C /opt/pangolin config
msg_ok "Created backup"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_amd64"
msg_info "Updating Pangolin"
cd /opt/pangolin
$STD npm ci
$STD npm run set:sqlite
$STD npm run set:oss
rm -rf server/private
$STD npm run db:generate
$STD npm run build
$STD npm run build:cli
cp -R .next/standalone ./
chmod +x ./dist/cli.mjs
cp server/db/names.json ./dist/names.json
cp server/db/ios_models.json ./dist/ios_models.json
cp server/db/mac_models.json ./dist/mac_models.json
msg_ok "Updated Pangolin"
msg_info "Restoring config"
tar -xzf /opt/pangolin_config_backup.tar.gz -C /opt/pangolin --overwrite
rm -f /opt/pangolin_config_backup.tar.gz
msg_ok "Restored config"
msg_info "Running database migrations"
cd /opt/pangolin
# Pre-apply potentially destructive schema changes safely so drizzle-kit
# does not recreate tables (which would delete all rows).
local DB="/opt/pangolin/config/db/db.sqlite"
if [[ -f "$DB" ]]; then
sqlite3 "$DB" "ALTER TABLE 'orgs' ADD COLUMN 'settingsLogRetentionDaysConnection' integer DEFAULT 0 NOT NULL;" 2>/dev/null || true
sqlite3 "$DB" "ALTER TABLE 'clientSitesAssociationsCache' ADD COLUMN 'isJitMode' integer DEFAULT 0 NOT NULL;" 2>/dev/null || true
# Create new role-mapping tables and migrate data before drizzle-kit
# drops the roleId columns from userOrgs and userInvites.
sqlite3 "$DB" "CREATE TABLE IF NOT EXISTS 'userOrgRoles' (
'userId' text NOT NULL REFERENCES 'user'('id') ON DELETE CASCADE,
'orgId' text NOT NULL REFERENCES 'orgs'('orgId') ON DELETE CASCADE,
'roleId' integer NOT NULL REFERENCES 'roles'('roleId') ON DELETE CASCADE,
UNIQUE('userId', 'orgId', 'roleId')
);" 2>/dev/null || true
sqlite3 "$DB" "INSERT OR IGNORE INTO 'userOrgRoles' (userId, orgId, roleId) SELECT userId, orgId, roleId FROM 'userOrgs' WHERE roleId IS NOT NULL;" 2>/dev/null || true
sqlite3 "$DB" "CREATE TABLE IF NOT EXISTS 'userInviteRoles' (
'inviteId' text NOT NULL REFERENCES 'userInvites'('inviteId') ON DELETE CASCADE,
'roleId' integer NOT NULL REFERENCES 'roles'('roleId') ON DELETE CASCADE,
PRIMARY KEY('inviteId', 'roleId')
);" 2>/dev/null || true
sqlite3 "$DB" "INSERT OR IGNORE INTO 'userInviteRoles' (inviteId, roleId) SELECT inviteId, roleId FROM 'userInvites' WHERE roleId IS NOT NULL;" 2>/dev/null || true
fi
ENVIRONMENT=prod $STD npx drizzle-kit push --force --config drizzle.sqlite.config.ts
msg_ok "Ran database migrations"
msg_info "Updating Badger plugin version"
BADGER_VERSION=$(get_latest_github_release "fosrl/badger" "false")
sed -i "s/version: \"v[0-9.]*\"/version: \"$BADGER_VERSION\"/g" /opt/pangolin/config/traefik/traefik_config.yml
msg_ok "Updated Badger plugin version"
msg_info "Starting Services"
systemctl start pangolin
systemctl start gerbil
msg_ok "Started Services"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}https://<YOUR_PANGOLIN_URL>${CL}"