vdi-cloud/tools/deploy-vdi-display-refresh.py

76 lines
3.6 KiB
Python

"""Back up and deploy the VDD login refresh script in VM100, without rebooting."""
import argparse
import base64
from pathlib import Path
import runpy
import sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
parser = argparse.ArgumentParser(description=__doc__)
parser.parse_args()
root = Path(__file__).resolve().parent
term = runpy.run_path(str(root / "pve_term_exec.py"))
vm = runpy.run_path(str(root / "pve_vm.py"))
ticket, csrf = term["login"]()
state = vm["api"]("/api2/json/nodes/starhe/qemu/100/status/current", ticket=ticket)
if state.get("status") != "running":
sys.exit("VM100 is not running; nothing changed")
payload = base64.b64encode((root / "set-2k-display.ps1").read_bytes()).decode()
command = r"""
$ErrorActionPreference='Stop'
$target='C:\ProgramData\VDI\set-2k-display.ps1'
$task='VDISet2KDisplay'
$entry=Get-ScheduledTask -TaskName $task
if($entry.State -eq 'Running') { throw 'Display task is already running; inspect before deployment' }
if(-not (Test-Path -LiteralPath $target)) { throw 'Original display script is missing' }
if(($entry.Actions | Select-Object -First 1).Arguments -notlike '*set-2k-display.ps1*') {
throw 'Unexpected display task action; do not change it'
}
$backup='C:\ProgramData\VDI\backups\display-refresh-'+(Get-Date -Format 'yyyyMMdd-HHmmss')
New-Item -ItemType Directory -Path $backup | Out-Null
Copy-Item -LiteralPath $target -Destination "$backup\set-2k-display.ps1"
Export-ScheduledTask -TaskName $task | Set-Content -Encoding UTF8 "$backup\VDISet2KDisplay.xml"
if(Test-Path 'C:\ProgramData\VDI\set-2k-result.txt') {
Copy-Item 'C:\ProgramData\VDI\set-2k-result.txt' "$backup\previous-result.txt"
}
$temporary=$target+'.new'
try {
[IO.File]::WriteAllBytes($temporary,[Convert]::FromBase64String('__PAYLOAD__'))
Move-Item -LiteralPath $temporary -Destination $target -Force
# Prove freshness by a newly created result file; scheduler LastRunTime can
# lag wall-clock time after VM clock correction and is not a reliable token.
Remove-Item -LiteralPath 'C:\ProgramData\VDI\set-2k-result.txt' -ErrorAction SilentlyContinue
Start-ScheduledTask -TaskName $task
Start-Sleep -Seconds 2
for($i=0;$i -lt 20;$i++) {
if((Get-ScheduledTask -TaskName $task).State -ne 'Running') { break }
Start-Sleep -Seconds 1
}
$info=Get-ScheduledTaskInfo -TaskName $task
if((Get-ScheduledTask -TaskName $task).State -eq 'Running' -or
$info.LastTaskResult -ne 0) {
throw 'New display task did not complete successfully'
}
$log=Get-Content 'C:\ProgramData\VDI\set-2k-result.txt' -Raw
if($log -notmatch 'result=0 mode=2560x1440@60') { throw '60Hz read-back missing in display task log' }
@{backup=$backup; task_result=$info.LastTaskResult; result=$log.Trim()} | ConvertTo-Json -Compress
} catch {
if(Test-Path 'C:\ProgramData\VDI\set-2k-result.txt') {
Copy-Item 'C:\ProgramData\VDI\set-2k-result.txt' "$backup\failed-result.txt"
Get-Content "$backup\failed-result.txt"
}
if($info) { $info | Select-Object LastTaskResult,LastRunTime | ConvertTo-Json -Compress }
Stop-ScheduledTask -TaskName $task -ErrorAction SilentlyContinue
Copy-Item -LiteralPath "$backup\set-2k-display.ps1" -Destination $target -Force
Start-ScheduledTask -TaskName $task
throw
} finally {
Remove-Item -LiteralPath $temporary -ErrorAction SilentlyContinue
}
""".replace("__PAYLOAD__", payload)
out, error = vm["agent"](ticket, csrf, ["powershell.exe", "-NoProfile", "-Command", command])
print(out)
if error or '"task_result":0' not in out:
print(error, file=sys.stderr)
sys.exit(1)