mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-13 19:09:50 +00:00
fix(postgres): preserve Coolify image tag during upgrade
Keep the running Coolify image tag when restarting the stack after PostgreSQL upgrade or rollback so compose does not fall back to latest.
This commit is contained in:
@@ -136,6 +136,20 @@ current_postgres_image() {
|
||||
docker inspect coolify-db --format '{{.Config.Image}}' 2>/dev/null
|
||||
}
|
||||
|
||||
current_coolify_image_tag() {
|
||||
local image
|
||||
local image_without_digest
|
||||
local last_segment
|
||||
|
||||
image=$(docker inspect coolify --format '{{.Config.Image}}' 2>/dev/null || true)
|
||||
image_without_digest="${image%@*}"
|
||||
last_segment="${image_without_digest##*/}"
|
||||
|
||||
if [[ "$last_segment" == *:* ]]; then
|
||||
printf '%s' "${last_segment##*:}"
|
||||
fi
|
||||
}
|
||||
|
||||
write_override_file() {
|
||||
local image="$1"
|
||||
local volume="$2"
|
||||
@@ -175,11 +189,12 @@ EOF
|
||||
}
|
||||
|
||||
start_stack() {
|
||||
local coolify_image_tag="${1:-${LATEST_IMAGE:-latest}}"
|
||||
local files
|
||||
files=$(compose_files)
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
LATEST_IMAGE="${LATEST_IMAGE:-latest}" docker compose --env-file "$ENV_FILE" $files up -d --remove-orphans --wait --wait-timeout 120
|
||||
LATEST_IMAGE="$coolify_image_tag" docker compose --env-file "$ENV_FILE" $files up -d --remove-orphans --wait --wait-timeout 120
|
||||
}
|
||||
|
||||
print_rollback_instructions() {
|
||||
@@ -220,10 +235,13 @@ rollback_postgres() {
|
||||
[ -n "${PREVIOUS_MOUNT_PATH:-}" ] || fail "Rollback metadata is missing PREVIOUS_MOUNT_PATH."
|
||||
[ -n "${PREVIOUS_OVERRIDE_PRESENT:-}" ] || fail "Rollback metadata is missing PREVIOUS_OVERRIDE_PRESENT."
|
||||
|
||||
CURRENT_COOLIFY_IMAGE_TAG=$(current_coolify_image_tag)
|
||||
|
||||
log "Rolling back Coolify internal PostgreSQL."
|
||||
log "Previous image: ${PREVIOUS_IMAGE}"
|
||||
log "Previous volume: ${PREVIOUS_VOLUME}"
|
||||
log "Previous mount path: ${PREVIOUS_MOUNT_PATH}"
|
||||
log "Current Coolify image tag: ${CURRENT_COOLIFY_IMAGE_TAG:-latest}"
|
||||
|
||||
docker volume inspect "$PREVIOUS_VOLUME" >/dev/null 2>&1 || fail "Previous volume '${PREVIOUS_VOLUME}' does not exist."
|
||||
|
||||
@@ -242,7 +260,7 @@ rollback_postgres() {
|
||||
fi
|
||||
|
||||
log "Starting Coolify stack with rollback database volume."
|
||||
start_stack >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack after rollback. See ${LOGFILE}."
|
||||
start_stack "$CURRENT_COOLIFY_IMAGE_TAG" >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack after rollback. See ${LOGFILE}."
|
||||
|
||||
log "Rollback completed successfully."
|
||||
cat <<EOF | tee -a "$LOGFILE"
|
||||
@@ -283,6 +301,7 @@ upgrade_postgres() {
|
||||
PREVIOUS_VOLUME=$(current_postgres_mount_name)
|
||||
PREVIOUS_MOUNT_PATH=$(current_postgres_mount_path)
|
||||
PREVIOUS_IMAGE=$(current_postgres_image)
|
||||
CURRENT_COOLIFY_IMAGE_TAG=$(current_coolify_image_tag)
|
||||
|
||||
[ -n "$PREVIOUS_VOLUME" ] || fail "Could not detect current PostgreSQL Docker volume."
|
||||
[ -n "$PREVIOUS_MOUNT_PATH" ] || fail "Could not detect current PostgreSQL mount path."
|
||||
@@ -298,6 +317,7 @@ upgrade_postgres() {
|
||||
log "Current active volume: ${PREVIOUS_VOLUME}"
|
||||
log "Current image: ${PREVIOUS_IMAGE}"
|
||||
log "Current mount path: ${PREVIOUS_MOUNT_PATH}"
|
||||
log "Current Coolify image tag: ${CURRENT_COOLIFY_IMAGE_TAG:-latest}"
|
||||
|
||||
if [ "$CURRENT_MAJOR" -eq "$TARGET_MAJOR" ]; then
|
||||
log "PostgreSQL is already on major ${TARGET_MAJOR}. Nothing to do."
|
||||
@@ -358,12 +378,16 @@ upgrade_postgres() {
|
||||
docker rm -f coolify-db >>"$LOGFILE" 2>&1 || true
|
||||
|
||||
log "Starting Coolify stack with PostgreSQL ${TARGET_MAJOR}."
|
||||
start_stack >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack with upgraded PostgreSQL. See ${LOGFILE}."
|
||||
start_stack "$CURRENT_COOLIFY_IMAGE_TAG" >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack with upgraded PostgreSQL. See ${LOGFILE}."
|
||||
|
||||
log "Coolify internal PostgreSQL upgrade completed successfully."
|
||||
print_rollback_instructions
|
||||
}
|
||||
|
||||
if [ "${COOLIFY_POSTGRES_UPGRADE_SOURCE_ONLY:-false}" = "true" ] && [ "${BASH_SOURCE[0]}" != "$0" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$COMMAND" in
|
||||
rollback)
|
||||
rollback_postgres
|
||||
|
||||
@@ -136,6 +136,20 @@ current_postgres_image() {
|
||||
docker inspect coolify-db --format '{{.Config.Image}}' 2>/dev/null
|
||||
}
|
||||
|
||||
current_coolify_image_tag() {
|
||||
local image
|
||||
local image_without_digest
|
||||
local last_segment
|
||||
|
||||
image=$(docker inspect coolify --format '{{.Config.Image}}' 2>/dev/null || true)
|
||||
image_without_digest="${image%@*}"
|
||||
last_segment="${image_without_digest##*/}"
|
||||
|
||||
if [[ "$last_segment" == *:* ]]; then
|
||||
printf '%s' "${last_segment##*:}"
|
||||
fi
|
||||
}
|
||||
|
||||
write_override_file() {
|
||||
local image="$1"
|
||||
local volume="$2"
|
||||
@@ -175,11 +189,12 @@ EOF
|
||||
}
|
||||
|
||||
start_stack() {
|
||||
local coolify_image_tag="${1:-${LATEST_IMAGE:-latest}}"
|
||||
local files
|
||||
files=$(compose_files)
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
LATEST_IMAGE="${LATEST_IMAGE:-latest}" docker compose --env-file "$ENV_FILE" $files up -d --remove-orphans --wait --wait-timeout 120
|
||||
LATEST_IMAGE="$coolify_image_tag" docker compose --env-file "$ENV_FILE" $files up -d --remove-orphans --wait --wait-timeout 120
|
||||
}
|
||||
|
||||
print_rollback_instructions() {
|
||||
@@ -220,10 +235,13 @@ rollback_postgres() {
|
||||
[ -n "${PREVIOUS_MOUNT_PATH:-}" ] || fail "Rollback metadata is missing PREVIOUS_MOUNT_PATH."
|
||||
[ -n "${PREVIOUS_OVERRIDE_PRESENT:-}" ] || fail "Rollback metadata is missing PREVIOUS_OVERRIDE_PRESENT."
|
||||
|
||||
CURRENT_COOLIFY_IMAGE_TAG=$(current_coolify_image_tag)
|
||||
|
||||
log "Rolling back Coolify internal PostgreSQL."
|
||||
log "Previous image: ${PREVIOUS_IMAGE}"
|
||||
log "Previous volume: ${PREVIOUS_VOLUME}"
|
||||
log "Previous mount path: ${PREVIOUS_MOUNT_PATH}"
|
||||
log "Current Coolify image tag: ${CURRENT_COOLIFY_IMAGE_TAG:-latest}"
|
||||
|
||||
docker volume inspect "$PREVIOUS_VOLUME" >/dev/null 2>&1 || fail "Previous volume '${PREVIOUS_VOLUME}' does not exist."
|
||||
|
||||
@@ -242,7 +260,7 @@ rollback_postgres() {
|
||||
fi
|
||||
|
||||
log "Starting Coolify stack with rollback database volume."
|
||||
start_stack >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack after rollback. See ${LOGFILE}."
|
||||
start_stack "$CURRENT_COOLIFY_IMAGE_TAG" >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack after rollback. See ${LOGFILE}."
|
||||
|
||||
log "Rollback completed successfully."
|
||||
cat <<EOF | tee -a "$LOGFILE"
|
||||
@@ -283,6 +301,7 @@ upgrade_postgres() {
|
||||
PREVIOUS_VOLUME=$(current_postgres_mount_name)
|
||||
PREVIOUS_MOUNT_PATH=$(current_postgres_mount_path)
|
||||
PREVIOUS_IMAGE=$(current_postgres_image)
|
||||
CURRENT_COOLIFY_IMAGE_TAG=$(current_coolify_image_tag)
|
||||
|
||||
[ -n "$PREVIOUS_VOLUME" ] || fail "Could not detect current PostgreSQL Docker volume."
|
||||
[ -n "$PREVIOUS_MOUNT_PATH" ] || fail "Could not detect current PostgreSQL mount path."
|
||||
@@ -298,6 +317,7 @@ upgrade_postgres() {
|
||||
log "Current active volume: ${PREVIOUS_VOLUME}"
|
||||
log "Current image: ${PREVIOUS_IMAGE}"
|
||||
log "Current mount path: ${PREVIOUS_MOUNT_PATH}"
|
||||
log "Current Coolify image tag: ${CURRENT_COOLIFY_IMAGE_TAG:-latest}"
|
||||
|
||||
if [ "$CURRENT_MAJOR" -eq "$TARGET_MAJOR" ]; then
|
||||
log "PostgreSQL is already on major ${TARGET_MAJOR}. Nothing to do."
|
||||
@@ -358,12 +378,16 @@ upgrade_postgres() {
|
||||
docker rm -f coolify-db >>"$LOGFILE" 2>&1 || true
|
||||
|
||||
log "Starting Coolify stack with PostgreSQL ${TARGET_MAJOR}."
|
||||
start_stack >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack with upgraded PostgreSQL. See ${LOGFILE}."
|
||||
start_stack "$CURRENT_COOLIFY_IMAGE_TAG" >>"$LOGFILE" 2>&1 || fail "Could not start Coolify stack with upgraded PostgreSQL. See ${LOGFILE}."
|
||||
|
||||
log "Coolify internal PostgreSQL upgrade completed successfully."
|
||||
print_rollback_instructions
|
||||
}
|
||||
|
||||
if [ "${COOLIFY_POSTGRES_UPGRADE_SOURCE_ONLY:-false}" = "true" ] && [ "${BASH_SOURCE[0]}" != "$0" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$COMMAND" in
|
||||
rollback)
|
||||
rollback_postgres
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
function runPostgresUpgradeScriptCommand(string $script): array
|
||||
{
|
||||
$root = base_path();
|
||||
$workingDirectory = sys_get_temp_dir().'/coolify-postgres-upgrade-test-'.Str::random(12);
|
||||
$binDirectory = $workingDirectory.'/bin';
|
||||
|
||||
mkdir($binDirectory, 0777, true);
|
||||
|
||||
file_put_contents($binDirectory.'/docker', <<<'BASH'
|
||||
#!/bin/bash
|
||||
if [ "$1" = "inspect" ]; then
|
||||
printf '%s\n' "${MOCK_DOCKER_IMAGE}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" = "compose" ]; then
|
||||
printf '%s\n' "${LATEST_IMAGE}" > "${MOCK_LATEST_IMAGE_OUTPUT}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit 1
|
||||
BASH);
|
||||
chmod($binDirectory.'/docker', 0755);
|
||||
|
||||
$outputFile = $workingDirectory.'/latest-image.txt';
|
||||
$command = sprintf(
|
||||
'PATH=%s:$PATH MOCK_LATEST_IMAGE_OUTPUT=%s COOLIFY_POSTGRES_UPGRADE_SOURCE_ONLY=true bash -c %s 2>&1',
|
||||
escapeshellarg($binDirectory),
|
||||
escapeshellarg($outputFile),
|
||||
escapeshellarg('cd '.escapeshellarg($root).'; '.$script),
|
||||
);
|
||||
|
||||
exec($command, $output, $exitCode);
|
||||
|
||||
return [$exitCode, implode("\n", $output), is_file($outputFile) ? trim(file_get_contents($outputFile)) : null];
|
||||
}
|
||||
|
||||
it('detects the current Coolify image tag from the running container image', function (string $scriptPath, string $image, string $expectedTag) {
|
||||
[$exitCode, $output] = runPostgresUpgradeScriptCommand(sprintf(
|
||||
'MOCK_DOCKER_IMAGE=%s; export MOCK_DOCKER_IMAGE; source %s; current_coolify_image_tag',
|
||||
escapeshellarg($image),
|
||||
escapeshellarg($scriptPath),
|
||||
));
|
||||
|
||||
expect($exitCode)->toBe(0)
|
||||
->and($output)->toBe($expectedTag);
|
||||
})->with([
|
||||
'nightly standard registry image' => ['other/nightly/upgrade-postgres.sh', 'ghcr.io/coollabsio/coolify:4.0.0-beta.420', '4.0.0-beta.420'],
|
||||
'nightly registry with port' => ['other/nightly/upgrade-postgres.sh', 'registry.example.com:5000/coollabsio/coolify:4.0.1', '4.0.1'],
|
||||
'nightly digest suffix' => ['other/nightly/upgrade-postgres.sh', 'ghcr.io/coollabsio/coolify:4.0.2@sha256:abcdef', '4.0.2'],
|
||||
'scripts standard registry image' => ['scripts/upgrade-postgres.sh', 'ghcr.io/coollabsio/coolify:4.0.0-beta.420', '4.0.0-beta.420'],
|
||||
'scripts registry with port' => ['scripts/upgrade-postgres.sh', 'registry.example.com:5000/coollabsio/coolify:4.0.1', '4.0.1'],
|
||||
'scripts digest suffix' => ['scripts/upgrade-postgres.sh', 'ghcr.io/coollabsio/coolify:4.0.2@sha256:abcdef', '4.0.2'],
|
||||
]);
|
||||
|
||||
it('passes the preserved Coolify image tag to docker compose when starting the stack', function (string $scriptPath) {
|
||||
[$exitCode, $output, $latestImage] = runPostgresUpgradeScriptCommand(
|
||||
sprintf('source %s; start_stack 4.0.0-beta.420', escapeshellarg($scriptPath)),
|
||||
);
|
||||
|
||||
expect($exitCode)->toBe(0)
|
||||
->and($output)->toBe('')
|
||||
->and($latestImage)->toBe('4.0.0-beta.420');
|
||||
})->with([
|
||||
'nightly script' => 'other/nightly/upgrade-postgres.sh',
|
||||
'release script' => 'scripts/upgrade-postgres.sh',
|
||||
]);
|
||||
Reference in New Issue
Block a user