Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions bin/revertfog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,11 @@ _candidateDumps() {
# ---------------------------------------------------------------------------
# Same problem as the dump and the same answer. configureHttpd() REMOVES an
# existing fog_web_<ver>.BACKUP before writing a new one, so a second
# installfog.sh run after a failed upgrade overwrites the 1.5 tree with the
# 1.6 one it just laid down -- and the directory name, which carries the
# version being installed, looks identical either way.
# installfog.sh run after a failed upgrade used to overwrite the 1.5 tree with
# the 1.6 one it just laid down -- and the directory name, which carries the
# version being installed, looks identical either way. The installer now
# renames a backup of another release after its own version first (GH-2000),
# but a server upgraded before that change may still hold only the 1.6 copy.
#
# 1.5 keeps its classes under lib/fog/ and has no src/; 1.6 is PSR-4 under
# src/ (ADR 0013) and has no lib/fog/. One file each way settles it.
Expand Down
11 changes: 7 additions & 4 deletions docs/release/1.6.0-release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,19 @@ persisted to .fogsettings (lib/common/functions.sh:6539). -->
- **Web tree:** `${DB_backup_path}/fog_web_<version>.BACKUP`
<!-- verified: lib/common/functions.sh:10483-10499. -->

Both are named after the version being upgraded *from*, not the one you're
upgrading to. Check `${DB_backup_path}` (default `/home/`, or whatever you
Both are named after the version being *installed*, not the one you are
upgrading from. The dump also carries a timestamp, so every run keeps its own.
If you run the installer a second time, the web backup from the first run holds
your 1.5 tree. The second run renames it after its own version
(`fog_web_<1.5 version>.BACKUP`) instead of replacing it. Check `${DB_backup_path}` (default `/home/`, or whatever you
passed to `-B` / recorded in `.fogsettings`) after the upgrade to confirm
both exist before you consider the run safe to walk away from.

### 3. If something goes wrong: reverting

`bin/revertfog.sh` restores a FOG install from the backups above. It must be
run as root, from the `bin/` directory of a **1.5** checkout — the one you
are going back to:
run as root, from the `bin/` directory of the **1.6** checkout you upgraded
with. A 1.5 checkout does not contain it:

```
Usage: ./revertfog.sh [-h?y] [--list] [--dump <path>] [--kernel-generation <N>] [--dry-run]
Expand Down
29 changes: 29 additions & 0 deletions lib/common/functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12840,6 +12840,34 @@ _warnUnrecognizedPlugins() {
echo " and re-run, or install them from that directory via the UI."
echo
}
# Keep a web backup that holds a DIFFERENT release, instead of deleting it.
#
# The backup is named after the version being installed, and configureHttpd()
# removes any existing one of that name before copying the current tree in. On
# the first 1.5 -> 1.6 run that directory holds the 1.5 tree. A second run of
# the same release then finds the 1.6 tree it laid down, and replacing the
# backup deleted the only copy of 1.5 -- the tree bin/revertfog.sh needs
# (GH-2000).
#
# So a backup whose own FOG_VERSION is not $version is renamed after its own
# version, with a timestamp if that name is taken. bin/revertfog.sh finds it by
# its fog_web_*.BACKUP glob. A backup of the same release is still replaced,
# exactly as before. The files are the version file of each layout: the
# generated 1.6 one, its tracked fallback, and 1.5's lib/fog/.
_setAsideOtherVersionWebBackup() {
local backup="${DB_backup_path}/fog_web_${version}.BACKUP"
[[ -d $backup ]] || return 0
local f="" held=""
for f in commons/version.php src/Base/System.php lib/fog/system.class.php; do
[[ -f $backup/$f ]] || continue
held="$(awk -F\' /"define\('FOG_VERSION'[,](.*)"/'{print $4}' "$backup/$f" | tr -d '[[:space:]]')"
[[ -n $held ]] && break
done
[[ -z $held || $held == "$version" ]] && return 0
local dest="${DB_backup_path}/fog_web_${held}.BACKUP"
[[ -e $dest ]] && dest="${DB_backup_path}/fog_web_${held}_$(date +%Y%m%d_%H%M%S).BACKUP"
mv "$backup" "$dest" >>$error_log 2>&1
}
configureHttpd() {
normalizeWebroot
# Both customizations trees, before anything below needs either of them.
Expand Down Expand Up @@ -13002,6 +13030,7 @@ configureHttpd() {
# the time that runs the evidence has been deleted. The list itself is
# $retiredplugins, defined at the top level beside those two functions.
retiredpluginsstripped=""
_setAsideOtherVersionWebBackup
if [[ -d ${DB_backup_path}/fog_web_${version}.BACKUP ]]; then
rm -rf ${DB_backup_path}/fog_web_${version}.BACKUP >>$error_log 2>&1
fi
Expand Down
114 changes: 114 additions & 0 deletions tests/web-backup-keeps-other-release.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/bin/bash
#
# A second install run keeps the web backup of the release it upgraded from.
#
# tests/web-backup-keeps-other-release.test.sh
#
# configureHttpd() names the web backup fog_web_${version}.BACKUP, after the
# version being INSTALLED, and removes any existing one before it copies the
# current tree in. A 1.5 -> 1.6 upgrade that is run twice therefore replaced the
# 1.5 tree with the 1.6 one, and bin/revertfog.sh had no web tree left to
# restore (GH-2000). _setAsideOtherVersionWebBackup() renames a backup of a
# different release out of the way instead.
#
# The function is EXECUTED against fixtures, not read.
#
# No root, no network, no FOG install.
#
# Usage: bash tests/web-backup-keeps-other-release.test.sh
# Exit status 0 = pass, 1 = fail.

root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
functions="$root/lib/common/functions.sh"

pass=0
fail=0

check() {
if [[ $2 -eq 0 ]]; then
pass=$((pass + 1))
else
fail=$((fail + 1))
printf ' FAIL %s\n' "$1"
fi
}

snippet=$(awk '
/^_setAsideOtherVersionWebBackup\(\) \{/ { grab = 1 }
grab { print }
grab && /^\}$/ { exit }
' "$functions")
if [[ -z $snippet ]]; then
echo "FAIL: could not find _setAsideOtherVersionWebBackup in lib/common/functions.sh" >&2
exit 1
fi
eval "$snippet"

# The backup step must call it before it removes the old backup.
grep -Pzo '_setAsideOtherVersionWebBackup\n if \[\[ -d \$\{DB_backup_path\}/fog_web_\$\{version\}\.BACKUP \]\]; then\n rm -rf' "$functions" >/dev/null
check "configureHttpd() calls it before removing fog_web_\${version}.BACKUP" $?

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
error_log="$work/error.log"
version="1.6.0-RC-19"

# Write a backup holding release $2 in the layout $3 (15, 16, 16fallback).
mkbackup() {
local dir="$DB_backup_path/$1"
case $3 in
15) mkdir -p "$dir/lib/fog"; printf "define('FOG_VERSION', '%s');\n" "$2" > "$dir/lib/fog/system.class.php" ;;
16) mkdir -p "$dir/commons" "$dir/src/Base"
printf "define('FOG_VERSION', '%s');\n" "$2" > "$dir/commons/version.php"
printf "define('FOG_VERSION', 'fallback');\n" > "$dir/src/Base/System.php" ;;
16fallback) mkdir -p "$dir/src/Base"; printf "define('FOG_VERSION', '%s');\n" "$2" > "$dir/src/Base/System.php" ;;
esac
touch "$dir/marker-$2"
}
reset() { rm -rf "$work/backup"; DB_backup_path="$work/backup"; mkdir -p "$DB_backup_path"; }

# --- the GH-2000 rerun: the backup holds 1.5 ---------------------------------
reset
mkbackup "fog_web_${version}.BACKUP" "1.5.10.2518" 15
_setAsideOtherVersionWebBackup
[[ ! -e $DB_backup_path/fog_web_${version}.BACKUP ]]
check "a 1.5 tree under the 1.6 name is moved off that name" $?
[[ -f $DB_backup_path/fog_web_1.5.10.2518.BACKUP/marker-1.5.10.2518 ]]
check "and kept, renamed after its own version" $?

# --- that name is already taken: keep both -----------------------------------
reset
mkbackup "fog_web_1.5.10.2518.BACKUP" "1.5.10.2518" 15
mkbackup "fog_web_${version}.BACKUP" "1.5.10.2518" 15
_setAsideOtherVersionWebBackup
n=$(find "$DB_backup_path" -maxdepth 1 -name 'fog_web_1.5.10.2518_*.BACKUP' | wc -l)
[[ $n -eq 1 && -d $DB_backup_path/fog_web_1.5.10.2518.BACKUP ]]
check "an existing backup of that release is not overwritten" $?

# --- an older 1.6 build, read from the generated version file ----------------
reset
mkbackup "fog_web_${version}.BACKUP" "1.6.0-RC-18" 16
_setAsideOtherVersionWebBackup
[[ -d $DB_backup_path/fog_web_1.6.0-RC-18.BACKUP && ! -e $DB_backup_path/fog_web_${version}.BACKUP ]]
check "a 1.6 tree's generated version.php wins over the fallback" $?

# --- the same release: left for the caller to replace, as before -------------
reset
mkbackup "fog_web_${version}.BACKUP" "$version" 16fallback
_setAsideOtherVersionWebBackup
[[ -f $DB_backup_path/fog_web_${version}.BACKUP/marker-$version ]]
check "a backup of the release being installed stays where it is" $?
[[ $(find "$DB_backup_path" -mindepth 1 -maxdepth 1 | wc -l) -eq 1 ]]
check "and nothing else is created" $?

# --- no backup, or one with no readable version ------------------------------
reset
_setAsideOtherVersionWebBackup
check "no backup: returns 0" $?
mkdir -p "$DB_backup_path/fog_web_${version}.BACKUP"
_setAsideOtherVersionWebBackup
[[ -d $DB_backup_path/fog_web_${version}.BACKUP ]]
check "an unreadable version leaves the backup to the old path" $?

echo "web backup keeps other release: $pass passed, $fail failed"
[[ $fail -eq 0 ]]
Loading