33 lines
2.3 KiB
PowerShell
33 lines
2.3 KiB
PowerShell
$ErrorActionPreference='Stop'
|
|
$PSNativeCommandUseErrorActionPreference=$true
|
|
$root=Split-Path -Parent $PSScriptRoot
|
|
Set-Location -LiteralPath $root
|
|
$suffix=[Guid]::NewGuid().ToString('N')
|
|
$restoreDatabase="voice_restore_verify_$suffix"
|
|
$dumpPath="/tmp/$restoreDatabase.dump"
|
|
if($restoreDatabase-notmatch'^voice_restore_verify_[a-f0-9]{32}$'){throw 'Unsafe restore verification database name'}
|
|
$started=[DateTime]::UtcNow
|
|
|
|
function Pg([Parameter(ValueFromRemainingArguments=$true)][string[]]$arguments){
|
|
$output=docker compose exec -T postgres @arguments
|
|
if($LASTEXITCODE-ne0){throw "PostgreSQL command failed: $($arguments -join ' ')"}
|
|
return ($output|Out-String).Trim()
|
|
}
|
|
|
|
try{
|
|
Pg @('pg_dump','-U','voice','-d','voice_platform','-Fc','--no-owner','--no-acl','-f',$dumpPath)|Out-Null
|
|
Pg @('createdb','-U','voice',$restoreDatabase)|Out-Null
|
|
Pg @('pg_restore','-U','voice','-d',$restoreDatabase,'--no-owner','--no-acl',$dumpPath)|Out-Null
|
|
$source=Pg @('psql','-U','voice','-d','voice_platform','-t','-A','-c',"SELECT version||'|'||dirty||'|'||(SELECT count(*) FROM tenant)||'|'||(SELECT count(*) FROM user_account) FROM schema_migrations")
|
|
$restored=Pg @('psql','-U','voice','-d',$restoreDatabase,'-t','-A','-c',"SELECT version||'|'||dirty||'|'||(SELECT count(*) FROM tenant)||'|'||(SELECT count(*) FROM user_account) FROM schema_migrations")
|
|
if($restored-ne$source){throw "Restored evidence mismatch. source=$source restored=$restored"}
|
|
$tableEvidence=Pg @('psql','-U','voice','-d',$restoreDatabase,'-t','-A','-c',"SELECT count(*) FROM information_schema.tables WHERE table_schema='public'; SELECT count(*) FROM information_schema.table_constraints WHERE constraint_type='FOREIGN KEY';")
|
|
$parts=@($tableEvidence-split"`n"|ForEach-Object{$_.Trim()}|Where-Object{$_})
|
|
if($parts.Count-ne2-or[int]$parts[0]-lt40-or[int]$parts[1]-lt30){throw "Restored schema inventory is incomplete: $tableEvidence"}
|
|
$elapsed=[Math]::Round(([DateTime]::UtcNow-$started).TotalSeconds,2)
|
|
Write-Host "PostgreSQL isolated restore passed: source/restored=$source, public_tables=$($parts[0]), foreign_keys=$($parts[1]), local_elapsed_seconds=$elapsed, database=$restoreDatabase"
|
|
}finally{
|
|
try{Pg @('dropdb','-U','voice','--if-exists',$restoreDatabase)|Out-Null}catch{Write-Warning $_}
|
|
try{Pg @('rm','-f',$dumpPath)|Out-Null}catch{Write-Warning $_}
|
|
}
|