220 lines
6.3 KiB
PowerShell
220 lines
6.3 KiB
PowerShell
$taskDefinitionCutoverContract = Join-Path $PSScriptRoot "public-runtime-task-definition-cutover.ps1"
|
|
if (-not (Test-Path -LiteralPath $taskDefinitionCutoverContract -PathType Leaf)) {
|
|
throw "Public runtime task definition cutover contract is unavailable"
|
|
}
|
|
. $taskDefinitionCutoverContract
|
|
|
|
function Assert-PublicRuntimeTasksDisabledAndIdle {
|
|
param(
|
|
[Parameter(Mandatory = $true)][object[]]$Snapshot,
|
|
[int]$TimeoutSec = 30
|
|
)
|
|
|
|
$deadline = (Get-Date).AddSeconds($TimeoutSec)
|
|
do {
|
|
$allDisabledAndIdle = $true
|
|
foreach ($entry in @($Snapshot)) {
|
|
if (-not [bool]$entry.exists) {
|
|
$unexpectedTask = Get-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction SilentlyContinue
|
|
if ($null -ne $unexpectedTask) {
|
|
throw "A coordinated public runtime task appeared during maintenance: $($entry.task_name)"
|
|
}
|
|
continue
|
|
}
|
|
$task = Get-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction Stop
|
|
if ([bool]$task.Settings.Enabled -or [string]$task.State -eq "Running") {
|
|
$allDisabledAndIdle = $false
|
|
break
|
|
}
|
|
}
|
|
if ($allDisabledAndIdle) {
|
|
return
|
|
}
|
|
Start-Sleep -Milliseconds 250
|
|
} while ((Get-Date) -lt $deadline)
|
|
|
|
throw "Public runtime scheduled tasks did not become disabled and idle"
|
|
}
|
|
|
|
function Get-PublicRuntimeTaskMaintenanceState {
|
|
param([Parameter(Mandatory = $true)][object[]]$Snapshot)
|
|
|
|
$allDisabledAndIdle = $true
|
|
$restoredToSnapshot = $true
|
|
$verified = $true
|
|
foreach ($entry in @($Snapshot)) {
|
|
if (-not [bool]$entry.exists) {
|
|
try {
|
|
$unexpectedTask = Get-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction SilentlyContinue
|
|
if ($null -ne $unexpectedTask) {
|
|
$allDisabledAndIdle = $false
|
|
$restoredToSnapshot = $false
|
|
}
|
|
} catch {
|
|
$verified = $false
|
|
$allDisabledAndIdle = $false
|
|
$restoredToSnapshot = $false
|
|
}
|
|
continue
|
|
}
|
|
try {
|
|
$task = Get-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction Stop
|
|
$isEnabled = [bool]$task.Settings.Enabled
|
|
$isRunning = [string]$task.State -eq "Running"
|
|
if ($isEnabled -or $isRunning) {
|
|
$allDisabledAndIdle = $false
|
|
}
|
|
if ($isEnabled -ne [bool]$entry.was_enabled) {
|
|
$restoredToSnapshot = $false
|
|
}
|
|
} catch {
|
|
$verified = $false
|
|
$allDisabledAndIdle = $false
|
|
$restoredToSnapshot = $false
|
|
}
|
|
}
|
|
|
|
return [pscustomobject][ordered]@{
|
|
verified = $verified
|
|
all_disabled_and_idle = $allDisabledAndIdle
|
|
restored_to_snapshot = $restoredToSnapshot
|
|
}
|
|
}
|
|
|
|
function Suspend-PublicRuntimeTasks {
|
|
param(
|
|
[Parameter(Mandatory = $true)][object[]]$Snapshot,
|
|
[int]$TimeoutSec = 30
|
|
)
|
|
|
|
foreach ($entry in @($Snapshot)) {
|
|
if (-not [bool]$entry.exists) {
|
|
continue
|
|
}
|
|
Disable-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction Stop `
|
|
| Out-Null
|
|
}
|
|
Assert-PublicRuntimeTasksDisabledAndIdle `
|
|
-Snapshot $Snapshot `
|
|
-TimeoutSec $TimeoutSec
|
|
}
|
|
|
|
function Enter-PublicRuntimeTaskMaintenance {
|
|
param(
|
|
[Parameter(Mandatory = $true)][string[]]$TaskNames,
|
|
[int]$TimeoutSec = 30
|
|
)
|
|
|
|
$snapshot = @()
|
|
try {
|
|
# 모든 원상복구 정보를 먼저 캡처한다. disable 도중 두 번째 task에서 오류가 나도
|
|
# 첫 번째 task를 포함한 완전한 snapshot으로 되돌릴 수 있어야 한다.
|
|
foreach ($taskName in @($TaskNames | Sort-Object -Unique)) {
|
|
if ([string]::IsNullOrWhiteSpace($taskName)) {
|
|
throw "Public runtime scheduled task name is empty"
|
|
}
|
|
$task = Get-ScheduledTask `
|
|
-TaskName $taskName `
|
|
-TaskPath "\" `
|
|
-ErrorAction SilentlyContinue
|
|
if ($null -eq $task) {
|
|
$snapshot += [pscustomobject][ordered]@{
|
|
task_name = $taskName
|
|
exists = $false
|
|
was_enabled = $false
|
|
}
|
|
continue
|
|
}
|
|
$wasEnabled = [bool]$task.Settings.Enabled
|
|
$snapshot += [pscustomobject][ordered]@{
|
|
task_name = $taskName
|
|
exists = $true
|
|
was_enabled = $wasEnabled
|
|
}
|
|
}
|
|
|
|
$result = @($snapshot)
|
|
Suspend-PublicRuntimeTasks `
|
|
-Snapshot $result `
|
|
-TimeoutSec $TimeoutSec
|
|
return $result
|
|
} catch {
|
|
foreach ($entry in @($snapshot)) {
|
|
if ([bool]$entry.exists -and [bool]$entry.was_enabled) {
|
|
Enable-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction SilentlyContinue `
|
|
| Out-Null
|
|
}
|
|
}
|
|
foreach ($entry in @($snapshot)) {
|
|
if (-not [bool]$entry.exists) {
|
|
continue
|
|
}
|
|
$task = Get-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction Stop
|
|
if ([bool]$task.Settings.Enabled -ne [bool]$entry.was_enabled) {
|
|
throw "Public runtime task maintenance entry rollback failed: $($entry.task_name)"
|
|
}
|
|
}
|
|
throw
|
|
}
|
|
}
|
|
|
|
function Exit-PublicRuntimeTaskMaintenance {
|
|
param([Parameter(Mandatory = $true)][object[]]$Snapshot)
|
|
|
|
try {
|
|
foreach ($entry in @($Snapshot)) {
|
|
if (-not [bool]$entry.exists -or -not [bool]$entry.was_enabled) {
|
|
continue
|
|
}
|
|
Enable-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction Stop `
|
|
| Out-Null
|
|
}
|
|
|
|
foreach ($entry in @($Snapshot)) {
|
|
if (-not [bool]$entry.exists -or -not [bool]$entry.was_enabled) {
|
|
continue
|
|
}
|
|
$task = Get-ScheduledTask `
|
|
-TaskName ([string]$entry.task_name) `
|
|
-TaskPath "\" `
|
|
-ErrorAction Stop
|
|
if (-not [bool]$task.Settings.Enabled) {
|
|
throw "Public runtime scheduled task was not re-enabled: $($entry.task_name)"
|
|
}
|
|
}
|
|
$restoredTruth = Get-PublicRuntimeTaskMaintenanceState -Snapshot $Snapshot
|
|
if (
|
|
-not [bool]$restoredTruth.verified -or
|
|
-not [bool]$restoredTruth.restored_to_snapshot
|
|
) {
|
|
throw "Public runtime scheduled task set drifted during maintenance"
|
|
}
|
|
} catch {
|
|
Suspend-PublicRuntimeTasks -Snapshot $Snapshot -TimeoutSec 30
|
|
throw
|
|
}
|
|
}
|