mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(installer): replace a stale installer before upgrading (#3235)
This commit is contained in:
@@ -2198,6 +2198,7 @@ async function verifyInstallerExecution(installerRoot: string): Promise<Array<st
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `${stubBin}${path.delimiter}${process.env.PATH ?? ''}`,
|
||||
FLUXER_INSTALLER_REFRESHED: '1',
|
||||
...(cwd == null ? {} : {PWD: cwd}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -128,6 +128,8 @@ Removing the line from `.env` also lets the upgrade run, and it is the wrong fix
|
||||
|
||||
Keep the installer beside the stack files. [Get started](/operator/get-started/#step-4-bring-up-the-instance) has the download and the checksum check for a fresh copy.
|
||||
|
||||
`--update` first compares the installer against the digest at `https://fluxer.dev/install.sh.sha256`. When the copy differs, it downloads the current one, checks it against that digest, and asks before it replaces the copy and runs it with the same options. Answering no, `--non-interactive`, or a run without a terminal stops before anything changes. On Windows the same check reads `https://fluxer.dev/install.ps1.sha256`.
|
||||
|
||||
See the plan first:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -59,11 +59,17 @@ param(
|
||||
[string[]]$Rest = @()
|
||||
)
|
||||
|
||||
$FluxerScriptArguments = @{}
|
||||
foreach ($entry in $PSBoundParameters.GetEnumerator()) {
|
||||
$FluxerScriptArguments[$entry.Key] = $entry.Value
|
||||
}
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
$FluxerRawBase = 'https://raw.githubusercontent.com/fluxerapp/fluxer'
|
||||
$FluxerInstallerUrl = 'https://fluxer.dev/install.ps1'
|
||||
$FluxerStackPath = 'deploy/self-hosting'
|
||||
$FluxerHealthPath = '/_health'
|
||||
$FluxerInitService = 'seaweedfs-init'
|
||||
@@ -1980,6 +1986,71 @@ function Assert-FluxerComposeFiles([string]$TargetDir, [string]$EnvPath) {
|
||||
}
|
||||
}
|
||||
|
||||
function Get-FluxerSha256([string]$Path) {
|
||||
return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
}
|
||||
|
||||
function Update-FluxerInstaller {
|
||||
if ($env:FLUXER_INSTALLER_REFRESHED) {
|
||||
return
|
||||
}
|
||||
$self = $PSCommandPath
|
||||
if (-not $self) {
|
||||
return
|
||||
}
|
||||
$selfDir = Split-Path -Parent $self
|
||||
if ($DryRun) {
|
||||
$staging = New-FluxerStagingDirectory ([System.IO.Path]::GetTempPath())
|
||||
} else {
|
||||
$staging = New-FluxerStagingDirectory $selfDir
|
||||
}
|
||||
try {
|
||||
$digestPath = Join-Path $staging 'install.ps1.sha256'
|
||||
try {
|
||||
Invoke-WebRequest -Uri "$FluxerInstallerUrl.sha256" -OutFile $digestPath -UseBasicParsing -MaximumRedirection 5 -TimeoutSec 60
|
||||
} catch {
|
||||
Write-FluxerLine "Could not reach $FluxerInstallerUrl.sha256, so this run goes on with $self."
|
||||
return
|
||||
}
|
||||
$published = ([System.IO.File]::ReadAllText($digestPath).Trim() -split '\s+')[0].ToLowerInvariant()
|
||||
if ($published -notmatch '^[0-9a-f]{64}$') {
|
||||
Stop-Fluxer "$FluxerInstallerUrl.sha256 holds no sha256 digest. Nothing was changed." $FluxerExitDownload
|
||||
}
|
||||
if ((Get-FluxerSha256 $self) -eq $published) {
|
||||
return
|
||||
}
|
||||
$fresh = Join-Path $staging 'install.ps1'
|
||||
try {
|
||||
Invoke-WebRequest -Uri $FluxerInstallerUrl -OutFile $fresh -UseBasicParsing -MaximumRedirection 5 -TimeoutSec 120
|
||||
} catch {
|
||||
Stop-Fluxer "Download failed for $FluxerInstallerUrl. Nothing was changed." $FluxerExitDownload
|
||||
}
|
||||
if ((Get-FluxerSha256 $fresh) -ne $published) {
|
||||
Stop-Fluxer "$FluxerInstallerUrl does not match the digest in $FluxerInstallerUrl.sha256. Nothing was changed." $FluxerExitDownload
|
||||
}
|
||||
Write-FluxerLine "$self differs from the installer $FluxerInstallerUrl serves. The stack files an upgrade downloads can require .env keys that only the current installer writes."
|
||||
if ($DryRun) {
|
||||
Write-FluxerLine 'The run asks to replace it with the current installer before it changes anything. The plan below is the one this copy would follow.'
|
||||
return
|
||||
}
|
||||
if ($NonInteractive -or [Console]::IsInputRedirected) {
|
||||
Stop-Fluxer "Nothing was changed. Download the current installer and run it:`n Invoke-WebRequest -Uri $FluxerInstallerUrl -OutFile install.ps1 -UseBasicParsing" $FluxerExitRefused
|
||||
}
|
||||
$answer = Read-Host -Prompt "Replace $self with the current installer and run that? [y/N]"
|
||||
if ($null -eq $answer -or $answer.Trim() -notmatch '^(y|yes)$') {
|
||||
Stop-Fluxer "Kept $self. Nothing was changed. Read the current installer at $FluxerInstallerUrl and run it once it is in place." $FluxerExitRefused
|
||||
}
|
||||
Move-Item -LiteralPath $fresh -Destination $self -Force
|
||||
} finally {
|
||||
Remove-FluxerStagingDirectory $staging
|
||||
}
|
||||
Write-FluxerLine "Replaced $self. Running it."
|
||||
$env:FLUXER_INSTALLER_REFRESHED = '1'
|
||||
$global:LASTEXITCODE = 0
|
||||
& $self @FluxerScriptArguments
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
function Invoke-FluxerInstall {
|
||||
if ($Help) {
|
||||
Show-FluxerUsage
|
||||
@@ -2022,6 +2093,10 @@ function Invoke-FluxerInstall {
|
||||
|
||||
Invoke-FluxerPreflight
|
||||
|
||||
if ($Update) {
|
||||
Update-FluxerInstaller
|
||||
}
|
||||
|
||||
$targetPath = $Dir
|
||||
$adoptedCwd = $false
|
||||
$fellBack = $false
|
||||
|
||||
@@ -51,6 +51,7 @@ LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
FLUXER_RAW_BASE='https://raw.githubusercontent.com/fluxerapp/fluxer'
|
||||
FLUXER_INSTALLER_URL='https://fluxer.dev/install.sh'
|
||||
FLUXER_STACK_PATH='deploy/self-hosting'
|
||||
FLUXER_MIN_ENGINE='24.0.0'
|
||||
# Podman numbers its releases on its own scale, so the Docker Engine floor says
|
||||
@@ -305,6 +306,18 @@ opt_no_volume_compression=0
|
||||
opt_skip_backup=0
|
||||
opt_allow_root=0
|
||||
|
||||
fluxer_self=''
|
||||
if [ -f "$0" ]; then
|
||||
case $0 in
|
||||
/*) fluxer_self=$0 ;;
|
||||
*) fluxer_self="$(pwd)/$0" ;;
|
||||
esac
|
||||
fi
|
||||
fluxer_self_args=''
|
||||
for fluxer_arg in "$@"; do
|
||||
fluxer_self_args="$fluxer_self_args '$(printf '%s' "$fluxer_arg" | sed "s/'/'\\\\''/g")'"
|
||||
done
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--domain)
|
||||
@@ -651,6 +664,74 @@ fluxer_prompt() {
|
||||
return 1
|
||||
}
|
||||
|
||||
fluxer_sha256() {
|
||||
openssl dgst -sha256 < "$1" | awk '{print $NF}'
|
||||
}
|
||||
|
||||
fluxer_drop_scratch() {
|
||||
fluxer_cleanup
|
||||
fluxer_scratch=''
|
||||
}
|
||||
|
||||
fluxer_refresh_installer() {
|
||||
[ -z "${FLUXER_INSTALLER_REFRESHED:-}" ] || return 0
|
||||
[ -n "$fluxer_self" ] || return 0
|
||||
fluxer_self_dir=$(dirname "$fluxer_self")
|
||||
if [ "$opt_dry_run" -eq 1 ]; then
|
||||
fluxer_open_scratch "${TMPDIR:-/tmp}"
|
||||
elif [ -w "$fluxer_self_dir" ]; then
|
||||
fluxer_open_scratch "$fluxer_self_dir"
|
||||
else
|
||||
fluxer_say "$fluxer_self_dir is not writable, so this run cannot check $fluxer_self against $FLUXER_INSTALLER_URL and goes on with it."
|
||||
return 0
|
||||
fi
|
||||
if ! curl -fsSL --proto '=https' --tlsv1.2 -o "$fluxer_scratch/install.sh.sha256" "$FLUXER_INSTALLER_URL.sha256"; then
|
||||
fluxer_say "Could not reach $FLUXER_INSTALLER_URL.sha256, so this run goes on with $fluxer_self."
|
||||
fluxer_drop_scratch
|
||||
return 0
|
||||
fi
|
||||
fluxer_published=$(awk 'NR == 1 {print $1}' "$fluxer_scratch/install.sh.sha256")
|
||||
case $fluxer_published in
|
||||
''|*[!0-9a-f]*) fluxer_fail 4 "$FLUXER_INSTALLER_URL.sha256 holds no sha256 digest. Nothing was changed." ;;
|
||||
esac
|
||||
if [ "$(fluxer_sha256 "$fluxer_self")" = "$fluxer_published" ]; then
|
||||
fluxer_drop_scratch
|
||||
return 0
|
||||
fi
|
||||
if ! curl -fsSL --proto '=https' --tlsv1.2 -o "$fluxer_scratch/install.sh" "$FLUXER_INSTALLER_URL"; then
|
||||
fluxer_fail 4 "Download failed for $FLUXER_INSTALLER_URL. Nothing was changed."
|
||||
fi
|
||||
if [ "$(fluxer_sha256 "$fluxer_scratch/install.sh")" != "$fluxer_published" ]; then
|
||||
fluxer_fail 4 "$FLUXER_INSTALLER_URL does not match the digest in $FLUXER_INSTALLER_URL.sha256. Nothing was changed."
|
||||
fi
|
||||
fluxer_say "$fluxer_self differs from the installer $FLUXER_INSTALLER_URL serves. The stack files an upgrade downloads can require .env keys that only the current installer writes."
|
||||
if [ "$opt_dry_run" -eq 1 ]; then
|
||||
fluxer_say 'The run asks to replace it with the current installer before it changes anything. The plan below is the one this copy would follow.'
|
||||
fluxer_drop_scratch
|
||||
return 0
|
||||
fi
|
||||
if [ "$opt_non_interactive" -eq 1 ] || [ ! -t 0 ]; then
|
||||
fluxer_fail 3 "Nothing was changed. Download the current installer and run it:
|
||||
curl -fsSLO $FLUXER_INSTALLER_URL"
|
||||
fi
|
||||
printf 'Replace %s with the current installer and run that? [y/N] ' "$fluxer_self" >&2
|
||||
fluxer_answer=''
|
||||
read -r fluxer_answer || true
|
||||
case $fluxer_answer in
|
||||
y|Y|yes|Yes|YES) ;;
|
||||
*) fluxer_fail 3 "Kept $fluxer_self. Nothing was changed. Read the current installer at $FLUXER_INSTALLER_URL and run it once it is in place." ;;
|
||||
esac
|
||||
if [ -x "$fluxer_self" ]; then
|
||||
chmod +x "$fluxer_scratch/install.sh"
|
||||
fi
|
||||
mv "$fluxer_scratch/install.sh" "$fluxer_self"
|
||||
fluxer_drop_scratch
|
||||
fluxer_say "Replaced $fluxer_self. Running it."
|
||||
FLUXER_INSTALLER_REFRESHED=1
|
||||
export FLUXER_INSTALLER_REFRESHED
|
||||
eval "exec sh \"\$fluxer_self\" $fluxer_self_args"
|
||||
}
|
||||
|
||||
fluxer_resolve_values() {
|
||||
if [ "$opt_update" -eq 1 ] || [ "$opt_rollback" -eq 1 ]; then
|
||||
return 0
|
||||
@@ -2100,6 +2181,10 @@ fluxer_preflight
|
||||
fluxer_validate_options
|
||||
fluxer_resolve_values
|
||||
|
||||
if [ "$opt_update" -eq 1 ]; then
|
||||
fluxer_refresh_installer
|
||||
fi
|
||||
|
||||
if [ "$opt_update" -eq 1 ] || [ "$opt_rollback" -eq 1 ]; then
|
||||
fluxer_require_instance
|
||||
fluxer_resolve_ref
|
||||
|
||||
Reference in New Issue
Block a user