test(ft546): verify read-only shadow operation
This commit is contained in:
112
tools/shadow/Start-Ft546Shadow.ps1
Normal file
112
tools/shadow/Start-Ft546Shadow.ps1
Normal file
@@ -0,0 +1,112 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$ConfirmReadOnlyShadow,
|
||||
[Parameter(Mandatory = $true)][string]$PreflightJson,
|
||||
[string]$JavaExecutable = 'java',
|
||||
[int]$MaximumPreflightAgeMinutes = 30
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-StrictMode -Version Latest
|
||||
. (Join-Path $PSScriptRoot 'ShadowScriptCommon.ps1')
|
||||
|
||||
if (-not $ConfirmReadOnlyShadow.IsPresent) {
|
||||
throw 'CONFIRM_READ_ONLY_SHADOW_REQUIRED'
|
||||
}
|
||||
$preflightPath = Resolve-ShadowFile $PreflightJson
|
||||
$preflight = Read-ShadowJson $preflightPath
|
||||
if (-not [bool]$preflight.success) { throw 'SUCCESSFUL_PREFLIGHT_REQUIRED' }
|
||||
$generatedAt = [DateTime]::Parse($preflight.generatedAtUtc).ToUniversalTime()
|
||||
if (([DateTime]::UtcNow - $generatedAt).TotalMinutes -gt `
|
||||
$MaximumPreflightAgeMinutes) {
|
||||
throw 'PREFLIGHT_EXPIRED'
|
||||
}
|
||||
if ($null -eq (Get-Process -Id ([int]$preflight.stable.pid) `
|
||||
-ErrorAction SilentlyContinue)) {
|
||||
throw 'STABLE_PROCESS_NOT_HEALTHY'
|
||||
}
|
||||
|
||||
$artifact = Resolve-ShadowFile $preflight.shadowArtifact.path
|
||||
$config = Resolve-ShadowFile $preflight.config.path
|
||||
$deployment = Resolve-ShadowDirectory $preflight.deploymentDirectory
|
||||
if (-not (Test-ShadowPathWithin $artifact $deployment) -or `
|
||||
-not (Test-ShadowPathWithin $config $deployment)) {
|
||||
throw 'SHADOW_FILES_MUST_BE_INSIDE_DEPLOYMENT_DIRECTORY'
|
||||
}
|
||||
if ((Get-ShadowSha256 $artifact) -ne $preflight.shadowArtifact.sha256) {
|
||||
throw 'SHADOW_ARTIFACT_CHANGED_AFTER_PREFLIGHT'
|
||||
}
|
||||
if ((Get-ShadowSha256 $config) -ne $preflight.config.sha256) {
|
||||
throw 'SHADOW_CONFIG_CHANGED_AFTER_PREFLIGHT'
|
||||
}
|
||||
if ((Get-ShadowSha256 $preflight.permissionReport.path) -ne `
|
||||
$preflight.permissionReport.sha256) {
|
||||
throw 'PERMISSION_REPORT_CHANGED_AFTER_PREFLIGHT'
|
||||
}
|
||||
if ((Get-ShadowSha256 $preflight.networkDenyReport.path) -ne `
|
||||
$preflight.networkDenyReport.sha256) {
|
||||
throw 'NETWORK_DENY_REPORT_CHANGED_AFTER_PREFLIGHT'
|
||||
}
|
||||
|
||||
$pidFile = [IO.Path]::GetFullPath($preflight.pidFile)
|
||||
if (-not (Test-ShadowPathWithin $pidFile $deployment)) {
|
||||
throw 'PID_FILE_MUST_BE_INSIDE_DEPLOYMENT_DIRECTORY'
|
||||
}
|
||||
if (Test-Path -LiteralPath $pidFile) { throw 'SHADOW_PID_FILE_ALREADY_EXISTS' }
|
||||
$java = (Get-Command $JavaExecutable -ErrorAction Stop).Source
|
||||
$logs = Join-Path $deployment 'logs'
|
||||
New-Item -ItemType Directory -Path $logs -Force | Out-Null
|
||||
$stdout = Join-Path $logs 'shadow-stdout.log'
|
||||
$stderr = Join-Path $logs 'shadow-stderr.log'
|
||||
$configUri = ([uri]$config).AbsoluteUri
|
||||
$statusUri = [uri]$preflight.statusUri
|
||||
$runtimeProperties = @(
|
||||
'--spring.profiles.active=shadow',
|
||||
'--shadow.enabled=true',
|
||||
"--spring.config.additional-location=$configUri",
|
||||
"--server.address=$($statusUri.Host)",
|
||||
"--server.port=$($statusUri.Port)",
|
||||
"--shadow.evidence.run.artifact-sha256=$($preflight.shadowArtifact.sha256)",
|
||||
"--shadow.evidence.run.configuration-sha256=$($preflight.config.sha256)",
|
||||
"--shadow.evidence.run.source-server=$($preflight.sourceIdentity.server)",
|
||||
"--shadow.evidence.run.source-database=$($preflight.sourceIdentity.database)",
|
||||
"--shadow.evidence.minimum-free-bytes=$($preflight.minimumFreeBytes)"
|
||||
)
|
||||
$quotedProperties = @($runtimeProperties | ForEach-Object {
|
||||
'"{0}"' -f $_.Replace('"', '\"')
|
||||
}) -join ' '
|
||||
$arguments = '-jar "{0}" {1}' -f $artifact.Replace('"', '\"'), `
|
||||
$quotedProperties
|
||||
|
||||
$process = $null
|
||||
try {
|
||||
$process = Start-Process -FilePath $java -ArgumentList $arguments `
|
||||
-WorkingDirectory $deployment -WindowStyle Hidden -PassThru `
|
||||
-RedirectStandardOutput $stdout -RedirectStandardError $stderr
|
||||
Start-Sleep -Milliseconds 300
|
||||
if ($process.HasExited) {
|
||||
throw "SHADOW_PROCESS_EXITED_EARLY:$($process.ExitCode)"
|
||||
}
|
||||
$record = [pscustomobject]@{
|
||||
schemaVersion = 1
|
||||
pid = [int]$process.Id
|
||||
processStartTimeUtc = $process.StartTime.ToUniversalTime().ToString('o')
|
||||
javaExecutable = [IO.Path]::GetFullPath($java)
|
||||
shadowArtifact = $artifact
|
||||
shadowArtifactSha256 = Get-ShadowSha256 $artifact
|
||||
config = $config
|
||||
configSha256 = Get-ShadowSha256 $config
|
||||
deploymentDirectory = $deployment
|
||||
preflightJson = $preflightPath
|
||||
preflightSha256 = Get-ShadowSha256 $preflightPath
|
||||
startedAtUtc = [DateTime]::UtcNow.ToString('o')
|
||||
}
|
||||
Write-ShadowJson -Value $record -Path $pidFile
|
||||
return $record
|
||||
}
|
||||
catch {
|
||||
if ($null -ne $process -and -not $process.HasExited) {
|
||||
Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
throw
|
||||
}
|
||||
Reference in New Issue
Block a user