mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-04 20:33:24 +01:00
Compare commits
1 Commits
ref_koilec
...
fix/php-mo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb8691493b |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -393,16 +393,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
## 2026-01-30
|
## 2026-01-30
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- core: meilisearch - add data migration for version upgrades [@MickLesk](https://github.com/MickLesk) ([#11356](https://github.com/community-scripts/ProxmoxVE/pull/11356))
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
|
|
||||||
|
|
||||||
## 2026-01-29
|
## 2026-01-29
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ EOF
|
|||||||
ln -s "$GEO_DIR" "$APP_DIR"
|
ln -s "$GEO_DIR" "$APP_DIR"
|
||||||
|
|
||||||
chown -R immich:immich "$INSTALL_DIR"
|
chown -R immich:immich "$INSTALL_DIR"
|
||||||
if [[ "${MAINT_MODE:-0}" == 1 ]]; then
|
if [[ "$MAINT_MODE" == 1 ]]; then
|
||||||
msg_info "Disabling Maintenance Mode"
|
msg_info "Disabling Maintenance Mode"
|
||||||
cd /opt/immich/app/bin
|
cd /opt/immich/app/bin
|
||||||
$STD bash ./immich-admin disable-maintenance-mode
|
$STD bash ./immich-admin disable-maintenance-mode
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ function update_script() {
|
|||||||
msg_info "Stopping Service"
|
msg_info "Stopping Service"
|
||||||
systemctl stop apache2
|
systemctl stop apache2
|
||||||
msg_ok "Stopped Service"
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
PHP_VERSION="8.5" PHP_APACHE="YES" setup_php
|
PHP_VERSION="8.5" PHP_APACHE="YES" PHP_MODULE="apcu,ctype,dom,fileinfo,iconv,pgsql" setup_php
|
||||||
|
|
||||||
msg_info "Creating a backup"
|
msg_info "Creating a backup"
|
||||||
mv /opt/koillection/ /opt/koillection-backup
|
mv /opt/koillection/ /opt/koillection-backup
|
||||||
@@ -45,7 +45,6 @@ function update_script() {
|
|||||||
cp -r /opt/koillection-backup/.env.local /opt/koillection
|
cp -r /opt/koillection-backup/.env.local /opt/koillection
|
||||||
cp -r /opt/koillection-backup/public/uploads/. /opt/koillection/public/uploads/
|
cp -r /opt/koillection-backup/public/uploads/. /opt/koillection/public/uploads/
|
||||||
export COMPOSER_ALLOW_SUPERUSER=1
|
export COMPOSER_ALLOW_SUPERUSER=1
|
||||||
export APP_RUNTIME='Symfony\Component\Runtime\SymfonyRuntime'
|
|
||||||
$STD composer install --no-dev -o --no-interaction --classmap-authoritative
|
$STD composer install --no-dev -o --no-interaction --classmap-authoritative
|
||||||
$STD php bin/console doctrine:migrations:migrate --no-interaction
|
$STD php bin/console doctrine:migrations:migrate --no-interaction
|
||||||
$STD php bin/console app:translations:dump
|
$STD php bin/console app:translations:dump
|
||||||
|
|||||||
@@ -13,11 +13,24 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
|
NODE_VERSION="22" NODE_MODULE="yarn@latest" setup_nodejs
|
||||||
PG_VERSION="16" setup_postgresql
|
PG_VERSION="16" setup_postgresql
|
||||||
PHP_VERSION="8.5" PHP_APACHE="YES" setup_php
|
PHP_VERSION="8.5" PHP_APACHE="YES" PHP_MODULE="apcu,ctype,dom,fileinfo,iconv,pgsql" setup_php
|
||||||
setup_composer
|
setup_composer
|
||||||
PG_DB_NAME="koillection" PG_DB_USER="koillection" setup_postgresql_db
|
|
||||||
|
msg_info "Setting up PostgreSQL"
|
||||||
|
DB_NAME=koillection
|
||||||
|
DB_USER=koillection
|
||||||
|
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)
|
||||||
|
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
||||||
|
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER TEMPLATE template0;"
|
||||||
|
{
|
||||||
|
echo "Koillection Credentials"
|
||||||
|
echo "Koillection Database User: $DB_USER"
|
||||||
|
echo "Koillection Database Password: $DB_PASS"
|
||||||
|
echo "Koillection Database Name: $DB_NAME"
|
||||||
|
} >>~/koillection.creds
|
||||||
|
msg_ok "Set up PostgreSQL"
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "koillection" "benjaminjonard/koillection" "tarball"
|
fetch_and_deploy_gh_release "koillection" "benjaminjonard/koillection" "tarball"
|
||||||
|
|
||||||
@@ -28,12 +41,11 @@ APP_SECRET=$(openssl rand -base64 32)
|
|||||||
sed -i -e "s|^APP_ENV=.*|APP_ENV=prod|" \
|
sed -i -e "s|^APP_ENV=.*|APP_ENV=prod|" \
|
||||||
-e "s|^APP_DEBUG=.*|APP_DEBUG=0|" \
|
-e "s|^APP_DEBUG=.*|APP_DEBUG=0|" \
|
||||||
-e "s|^APP_SECRET=.*|APP_SECRET=${APP_SECRET}|" \
|
-e "s|^APP_SECRET=.*|APP_SECRET=${APP_SECRET}|" \
|
||||||
-e "s|^DB_NAME=.*|DB_NAME=${PG_DB_NAME}|" \
|
-e "s|^DB_NAME=.*|DB_NAME=${DB_NAME}|" \
|
||||||
-e "s|^DB_USER=.*|DB_USER=${PG_DB_USER}|" \
|
-e "s|^DB_USER=.*|DB_USER=${DB_USER}|" \
|
||||||
-e "s|^DB_PASSWORD=.*|DB_PASSWORD=${PG_DB_PASS}|" \
|
-e "s|^DB_PASSWORD=.*|DB_PASSWORD=${DB_PASS}|" \
|
||||||
/opt/koillection/.env.local
|
/opt/koillection/.env.local
|
||||||
export COMPOSER_ALLOW_SUPERUSER=1
|
export COMPOSER_ALLOW_SUPERUSER=1
|
||||||
export APP_RUNTIME='Symfony\Component\Runtime\SymfonyRuntime'
|
|
||||||
$STD composer install --no-dev -o --no-interaction --classmap-authoritative
|
$STD composer install --no-dev -o --no-interaction --classmap-authoritative
|
||||||
$STD php bin/console doctrine:migrations:migrate --no-interaction
|
$STD php bin/console doctrine:migrations:migrate --no-interaction
|
||||||
$STD php bin/console app:translations:dump
|
$STD php bin/console app:translations:dump
|
||||||
|
|||||||
162
misc/tools.func
162
misc/tools.func
@@ -5259,169 +5259,9 @@ function setup_meilisearch() {
|
|||||||
if [[ -f /usr/bin/meilisearch ]]; then
|
if [[ -f /usr/bin/meilisearch ]]; then
|
||||||
if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then
|
if check_for_gh_release "meilisearch" "meilisearch/meilisearch"; then
|
||||||
msg_info "Updating MeiliSearch"
|
msg_info "Updating MeiliSearch"
|
||||||
|
|
||||||
# Get current and new version for compatibility check
|
|
||||||
local CURRENT_VERSION NEW_VERSION
|
|
||||||
CURRENT_VERSION=$(/usr/bin/meilisearch --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) || CURRENT_VERSION="0.0.0"
|
|
||||||
NEW_VERSION="${CHECK_UPDATE_RELEASE#v}"
|
|
||||||
|
|
||||||
# Extract major.minor for comparison (Meilisearch requires dump/restore between minor versions)
|
|
||||||
local CURRENT_MAJOR_MINOR NEW_MAJOR_MINOR
|
|
||||||
CURRENT_MAJOR_MINOR=$(echo "$CURRENT_VERSION" | cut -d. -f1,2)
|
|
||||||
NEW_MAJOR_MINOR=$(echo "$NEW_VERSION" | cut -d. -f1,2)
|
|
||||||
|
|
||||||
# Determine if migration is needed (different major.minor = incompatible DB format)
|
|
||||||
local NEEDS_MIGRATION=false
|
|
||||||
if [[ "$CURRENT_MAJOR_MINOR" != "$NEW_MAJOR_MINOR" ]]; then
|
|
||||||
NEEDS_MIGRATION=true
|
|
||||||
msg_info "MeiliSearch version change detected (${CURRENT_VERSION} → ${NEW_VERSION}), preparing data migration"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Read config values for dump/restore
|
|
||||||
local MEILI_HOST MEILI_PORT MEILI_MASTER_KEY MEILI_DUMP_DIR
|
|
||||||
MEILI_HOST="${MEILISEARCH_HOST:-127.0.0.1}"
|
|
||||||
MEILI_PORT="${MEILISEARCH_PORT:-7700}"
|
|
||||||
MEILI_DUMP_DIR="${MEILISEARCH_DUMP_DIR:-/var/lib/meilisearch/dumps}"
|
|
||||||
MEILI_MASTER_KEY=$(grep -E "^master_key\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ')
|
|
||||||
|
|
||||||
# Create dump before update if migration is needed
|
|
||||||
local DUMP_UID=""
|
|
||||||
if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$MEILI_MASTER_KEY" ]]; then
|
|
||||||
msg_info "Creating MeiliSearch data dump before upgrade"
|
|
||||||
|
|
||||||
# Trigger dump creation
|
|
||||||
local DUMP_RESPONSE
|
|
||||||
DUMP_RESPONSE=$(curl -s -X POST "http://${MEILI_HOST}:${MEILI_PORT}/dumps" \
|
|
||||||
-H "Authorization: Bearer ${MEILI_MASTER_KEY}" \
|
|
||||||
-H "Content-Type: application/json" 2>/dev/null) || true
|
|
||||||
|
|
||||||
# The initial response only contains taskUid, not dumpUid
|
|
||||||
# dumpUid is only available after the task completes
|
|
||||||
local TASK_UID
|
|
||||||
TASK_UID=$(echo "$DUMP_RESPONSE" | grep -oP '"taskUid":\s*\K[0-9]+' || true)
|
|
||||||
|
|
||||||
if [[ -n "$TASK_UID" ]]; then
|
|
||||||
msg_info "Waiting for dump task ${TASK_UID} to complete..."
|
|
||||||
local MAX_WAIT=120
|
|
||||||
local WAITED=0
|
|
||||||
local TASK_RESULT=""
|
|
||||||
|
|
||||||
while [[ $WAITED -lt $MAX_WAIT ]]; do
|
|
||||||
TASK_RESULT=$(curl -s "http://${MEILI_HOST}:${MEILI_PORT}/tasks/${TASK_UID}" \
|
|
||||||
-H "Authorization: Bearer ${MEILI_MASTER_KEY}" 2>/dev/null) || true
|
|
||||||
|
|
||||||
local TASK_STATUS
|
|
||||||
TASK_STATUS=$(echo "$TASK_RESULT" | grep -oP '"status":\s*"\K[^"]+' || true)
|
|
||||||
|
|
||||||
if [[ "$TASK_STATUS" == "succeeded" ]]; then
|
|
||||||
# Extract dumpUid from the completed task details
|
|
||||||
DUMP_UID=$(echo "$TASK_RESULT" | grep -oP '"dumpUid":\s*"\K[^"]+' || true)
|
|
||||||
if [[ -n "$DUMP_UID" ]]; then
|
|
||||||
msg_ok "MeiliSearch dump created successfully: ${DUMP_UID}"
|
|
||||||
else
|
|
||||||
msg_warn "Dump task succeeded but could not extract dumpUid"
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
elif [[ "$TASK_STATUS" == "failed" ]]; then
|
|
||||||
local ERROR_MSG
|
|
||||||
ERROR_MSG=$(echo "$TASK_RESULT" | grep -oP '"message":\s*"\K[^"]+' || echo "Unknown error")
|
|
||||||
msg_warn "MeiliSearch dump failed: ${ERROR_MSG}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 2
|
|
||||||
WAITED=$((WAITED + 2))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $WAITED -ge $MAX_WAIT ]]; then
|
|
||||||
msg_warn "MeiliSearch dump timed out after ${MAX_WAIT}s"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
msg_warn "Could not trigger MeiliSearch dump (no taskUid in response)"
|
|
||||||
msg_info "Response was: ${DUMP_RESPONSE:-empty}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If migration is needed but dump failed, we have options:
|
|
||||||
# 1. Abort the update (safest, but annoying)
|
|
||||||
# 2. Backup data directory and proceed (allows manual recovery)
|
|
||||||
# 3. Just proceed and hope for the best (dangerous)
|
|
||||||
# We choose option 2: backup and proceed with warning
|
|
||||||
if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -z "$DUMP_UID" ]]; then
|
|
||||||
local MEILI_DB_PATH
|
|
||||||
MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ')
|
|
||||||
MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}"
|
|
||||||
|
|
||||||
if [[ -d "$MEILI_DB_PATH" ]] && [[ -n "$(ls -A "$MEILI_DB_PATH" 2>/dev/null)" ]]; then
|
|
||||||
local BACKUP_PATH="${MEILI_DB_PATH}.backup.$(date +%Y%m%d%H%M%S)"
|
|
||||||
msg_warn "Backing up MeiliSearch data to ${BACKUP_PATH}"
|
|
||||||
mv "$MEILI_DB_PATH" "$BACKUP_PATH"
|
|
||||||
mkdir -p "$MEILI_DB_PATH"
|
|
||||||
msg_info "Data backed up. After update, you may need to reindex your data."
|
|
||||||
msg_info "Old data is preserved at: ${BACKUP_PATH}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Stop service and update binary
|
|
||||||
systemctl stop meilisearch
|
systemctl stop meilisearch
|
||||||
fetch_and_deploy_gh_release "meilisearch" "meilisearch/meilisearch" "binary"
|
fetch_and_deploy_gh_release "meilisearch" "meilisearch/meilisearch" "binary"
|
||||||
|
systemctl start meilisearch
|
||||||
# If migration needed and dump was created, remove old data and import dump
|
|
||||||
if [[ "$NEEDS_MIGRATION" == "true" ]] && [[ -n "$DUMP_UID" ]]; then
|
|
||||||
local MEILI_DB_PATH
|
|
||||||
MEILI_DB_PATH=$(grep -E "^db_path\s*=" /etc/meilisearch.toml 2>/dev/null | sed 's/.*=\s*"\(.*\)"/\1/' | tr -d ' ')
|
|
||||||
MEILI_DB_PATH="${MEILI_DB_PATH:-/var/lib/meilisearch/data}"
|
|
||||||
|
|
||||||
msg_info "Removing old MeiliSearch database for migration"
|
|
||||||
rm -rf "${MEILI_DB_PATH:?}"/*
|
|
||||||
|
|
||||||
# Import dump using CLI flag (this is the supported method)
|
|
||||||
local DUMP_FILE="${MEILI_DUMP_DIR}/${DUMP_UID}.dump"
|
|
||||||
if [[ -f "$DUMP_FILE" ]]; then
|
|
||||||
msg_info "Importing dump: ${DUMP_FILE}"
|
|
||||||
|
|
||||||
# Start meilisearch with --import-dump flag
|
|
||||||
# This is a one-time import that happens during startup
|
|
||||||
/usr/bin/meilisearch --config-file-path /etc/meilisearch.toml --import-dump "$DUMP_FILE" &
|
|
||||||
local MEILI_PID=$!
|
|
||||||
|
|
||||||
# Wait for meilisearch to become healthy (import happens during startup)
|
|
||||||
msg_info "Waiting for MeiliSearch to import and start..."
|
|
||||||
local MAX_WAIT=300
|
|
||||||
local WAITED=0
|
|
||||||
while [[ $WAITED -lt $MAX_WAIT ]]; do
|
|
||||||
if curl -sf "http://${MEILI_HOST}:${MEILI_PORT}/health" &>/dev/null; then
|
|
||||||
msg_ok "MeiliSearch is healthy after import"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
# Check if process is still running
|
|
||||||
if ! kill -0 $MEILI_PID 2>/dev/null; then
|
|
||||||
msg_warn "MeiliSearch process exited during import"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep 3
|
|
||||||
WAITED=$((WAITED + 3))
|
|
||||||
done
|
|
||||||
|
|
||||||
# Stop the manual process
|
|
||||||
kill $MEILI_PID 2>/dev/null || true
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
# Start via systemd for proper management
|
|
||||||
systemctl start meilisearch
|
|
||||||
|
|
||||||
if systemctl is-active --quiet meilisearch; then
|
|
||||||
msg_ok "MeiliSearch migrated successfully"
|
|
||||||
else
|
|
||||||
msg_warn "MeiliSearch failed to start after migration - check logs with: journalctl -u meilisearch"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
msg_warn "Dump file not found: ${DUMP_FILE}"
|
|
||||||
systemctl start meilisearch
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
systemctl start meilisearch
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "Updated MeiliSearch"
|
msg_ok "Updated MeiliSearch"
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user