Give the console a repair verb, and something real to check
A server whose migrations or seeds never finished does not fail politely. Most
pages answer 500 and settings endpoints answer 404 for keys that were never
created, which reads as a broken application rather than an unfinished install.
One site spent a morning being debugged that way.
`shopdb-admin.ps1 repair` runs what stage 3 of the installer runs: db upgrade,
plugin upgrade-all, and the three seeds. Every step is idempotent, so running it
on a healthy server changes nothing, and each step runs independently so one
failure does not silently skip the rest.
`check` now says so before anyone has to infer it:
THIS SERVER IS NOT FULLY PROVISIONED
- seed data is missing (permissions, settings or reference data)
Most pages will answer 500 until this is fixed. Run:
shopdb-admin.ps1 repair
That needs a real test to sit on, so `flask db-utils seed-state` reports each
seed group and exits non-zero when any is missing. Verified by emptying the
settings table inside a transaction: MISSING, exit 1, rollback clean. Without it
the console check would have looked reassuring while testing nothing - an older
build with no such command reports UNKNOWN rather than healthy, for the same
reason.
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet('menu','status','start','stop','restart','logs','open','backup',
|
||||
'check','sessions','plugins','add-plugin','verify','uninstall')]
|
||||
'check','repair','sessions','plugins','add-plugin','verify','uninstall')]
|
||||
[string] $Command = 'menu',
|
||||
[string] $Path = '',
|
||||
# Machine-readable output for 'check'. The people running this are expected to
|
||||
@@ -577,11 +577,101 @@ function Invoke-Check {
|
||||
$env:FLASK_APP = 'shopdb'
|
||||
try { & $flask db-utils preflight 2>&1 | ForEach-Object { Say " $_" } }
|
||||
finally { Pop-Location }
|
||||
|
||||
# Surface an unfinished install HERE, where somebody is already looking,
|
||||
# rather than leaving them to infer it from 500s on unrelated pages.
|
||||
$state = Test-Provisioned
|
||||
if ($state.SchemaCurrent -eq $false -or $state.Seeded -eq $false) {
|
||||
Say ''
|
||||
Say ' THIS SERVER IS NOT FULLY PROVISIONED' 'Red'
|
||||
foreach ($detail in $state.Detail) { Say (" - {0}" -f $detail) 'Red' }
|
||||
Say ' Most pages will answer 500 until this is fixed. Run:' 'Yellow'
|
||||
Say ' shopdb-admin.ps1 repair' 'White'
|
||||
}
|
||||
|
||||
Say ''
|
||||
Say ' For help from an AI assistant, paste the output of:' 'DarkGray'
|
||||
Say ' shopdb-admin.ps1 check -Json' 'White'
|
||||
}
|
||||
|
||||
function Test-Provisioned {
|
||||
"""Is the schema current and the reference data seeded?"""
|
||||
# A server whose migrations or seeds never completed does not fail politely:
|
||||
# it answers 500 on most pages and 404 on settings that were never created,
|
||||
# which reads as a broken application rather than an unfinished install. One
|
||||
# site was stood up that way and spent a morning being debugged as a bug.
|
||||
$result = @{ SchemaCurrent = $true; Seeded = $true; Detail = @() }
|
||||
|
||||
$out = Invoke-Flask @('db','current')
|
||||
$current = ($out | Out-String)
|
||||
$head = (Invoke-Flask @('db','heads') | Out-String)
|
||||
if ($script:LastFlaskExit -ne 0) {
|
||||
$result.SchemaCurrent = $false
|
||||
$result.Detail += 'could not read the schema version'
|
||||
} elseif ($current -notmatch '\(head\)' -and $head.Trim()) {
|
||||
# `db current` appends "(head)" when the database is at the newest
|
||||
# revision. Its absence means migrations are outstanding.
|
||||
$result.SchemaCurrent = $false
|
||||
$result.Detail += 'database schema is behind the application'
|
||||
}
|
||||
|
||||
# Sentinel seeds. permissions, settings and the reference data are each
|
||||
# created by a `flask seed` command, and their absence is what produced the
|
||||
# 404s on settings keys at a site whose install never finished.
|
||||
$seedOut = (Invoke-Flask @('db-utils','seed-state') | Out-String)
|
||||
if ($seedOut -match 'No such command') {
|
||||
# An older build with no seed-state. Report UNKNOWN rather than healthy:
|
||||
# claiming a clean bill of health from a check that did not run is how a
|
||||
# broken server passes inspection.
|
||||
$result.Seeded = $null
|
||||
$result.Detail += 'seed state could not be checked (older build)'
|
||||
} elseif ($script:LastFlaskExit -ne 0 -or $seedOut -match 'MISSING') {
|
||||
$result.Seeded = $false
|
||||
$result.Detail += 'seed data is missing (permissions, settings or reference data)'
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
function Invoke-Repair {
|
||||
Head 'Repair provisioning'
|
||||
Say ' Brings the database up to the application: migrations, plugin'
|
||||
Say ' migrations, and the seed data. Every step is idempotent, so running'
|
||||
Say ' this on a healthy server changes nothing.'
|
||||
Say ''
|
||||
|
||||
$steps = @(
|
||||
@{ Name = 'core schema'; Args = @('db','upgrade') },
|
||||
@{ Name = 'plugin schemas'; Args = @('plugin','upgrade-all') },
|
||||
@{ Name = 'permissions'; Args = @('seed','permissions') },
|
||||
@{ Name = 'settings'; Args = @('seed','settings') },
|
||||
@{ Name = 'reference data'; Args = @('seed','reference-data') }
|
||||
)
|
||||
$failed = @()
|
||||
foreach ($step in $steps) {
|
||||
Say (" {0} ..." -f $step.Name) 'White'
|
||||
$out = Invoke-Flask $step.Args
|
||||
if ($script:LastFlaskExit -ne 0) {
|
||||
$failed += $step.Name
|
||||
Say (" FAILED (exit {0})" -f $script:LastFlaskExit) 'Red'
|
||||
$out | Select-Object -Last 6 | ForEach-Object { Say " $_" 'Red' }
|
||||
} else {
|
||||
Say ' done' 'Green'
|
||||
}
|
||||
}
|
||||
|
||||
if ($failed.Count -gt 0) {
|
||||
Say ''
|
||||
Say (" {0} step(s) failed: {1}" -f $failed.Count, ($failed -join ', ')) 'Red'
|
||||
Say ' Nothing further was skipped - each step ran independently.' 'Red'
|
||||
Say ' Send the output above, or run: shopdb-admin.ps1 check -Json' 'Red'
|
||||
return
|
||||
}
|
||||
|
||||
Say ''
|
||||
Say ' Provisioning complete. Restarting the application.' 'Green'
|
||||
Restart-App
|
||||
}
|
||||
|
||||
function Show-Sessions {
|
||||
Head 'Worker processes'
|
||||
$w = Get-CimInstance Win32_Process -Filter "Name='w3wp.exe'" -EA SilentlyContinue
|
||||
@@ -856,6 +946,7 @@ switch ($Command) {
|
||||
'open' { Open-Site }
|
||||
'backup' { Backup-Db $Path }
|
||||
'check' { Invoke-Check }
|
||||
'repair' { Invoke-Repair }
|
||||
'sessions' { Show-Sessions }
|
||||
'plugins' { Show-Plugins }
|
||||
'add-plugin'{ Add-Plugin $Path }
|
||||
|
||||
Reference in New Issue
Block a user