# Install a CIS490 trainer worker on a Windows host (e.g., the operator's # desktop with the GPU). # # Symmetric to install-training-worker.sh but for Windows. Sets up: # - Confirms WireGuard reachability to the Pi receiver # - Confirms a Python venv with torch (CUDA) is present # - Registers a Scheduled Task that runs the worker at startup + every # 5 minutes if it isn't running # # Run as Administrator in PowerShell: # powershell.exe -ExecutionPolicy Bypass -File install-training-worker-windows.ps1 # # Prereqs (set up these manually before running): # - Git clone of the CIS490 repo at $env:CIS490_HOME (default: C:\cis490) # - Python 3.11+ in $env:CIS490_HOME\.venv with torch (CUDA) + xgboost # py -3.11 -m venv .venv # .\.venv\Scripts\pip install torch --index-url https://download.pytorch.org/whl/cu121 # .\.venv\Scripts\pip install -e . # - WireGuard tunnel up to 10.100.0.1 # # After install, the worker logs go to $env:CIS490_HOME\logs\trainer-worker.log param( [string]$RepoRoot = $(if ($env:CIS490_HOME) { $env:CIS490_HOME } else { "C:\cis490" }), [string]$ReceiverUrl = $(if ($env:CIS490_TRAINER_RECEIVER_URL) { $env:CIS490_TRAINER_RECEIVER_URL } else { "http://10.100.0.1:8445" }), [string]$HostId = $(if ($env:FLEET_HOST_ID) { $env:FLEET_HOST_ID } else { $env:COMPUTERNAME }) ) $ErrorActionPreference = "Stop" if (-not (Test-Path $RepoRoot)) { Write-Error "Repo not found at $RepoRoot. Set `$env:CIS490_HOME or pass -RepoRoot." exit 1 } $VenvPy = Join-Path $RepoRoot ".venv\Scripts\python.exe" if (-not (Test-Path $VenvPy)) { Write-Error @" No Python venv at $VenvPy. Set up first: cd $RepoRoot py -3.11 -m venv .venv .\.venv\Scripts\pip install torch --index-url https://download.pytorch.org/whl/cu121 .\.venv\Scripts\pip install -e . "@ exit 1 } # Receiver reachability Write-Host "Checking trainer-receiver at $ReceiverUrl..." try { $r = Invoke-WebRequest -Uri "$ReceiverUrl/v1/health" -TimeoutSec 5 -UseBasicParsing if ($r.StatusCode -ne 200) { throw "non-200" } Write-Host " receiver OK" } catch { Write-Error @" Cannot reach $ReceiverUrl. - Is the WireGuard tunnel up? (Get-NetAdapter | ? Name -like 'wg*') - Is cis490-trainer-receiver.service running on the Pi? "@ exit 1 } # Capability self-test Write-Host "" Write-Host "=== capability self-report ===" & $VenvPy -m training.fleet.capability Write-Host "" # Logs dir $LogsDir = Join-Path $RepoRoot "logs" New-Item -ItemType Directory -Force -Path $LogsDir | Out-Null $LogPath = Join-Path $LogsDir "trainer-worker.log" # Build the launcher .cmd that the scheduled task invokes $LauncherPath = Join-Path $RepoRoot "scripts\run-trainer-worker.cmd" @" @echo off cd /d "$RepoRoot" set CIS490_TRAINER_RECEIVER_URL=$ReceiverUrl set FLEET_HOST_ID=$HostId "$VenvPy" -m training.fleet.worker --receiver-url "$ReceiverUrl" --host-id "$HostId" >> "$LogPath" 2>&1 "@ | Set-Content -Encoding ASCII $LauncherPath Write-Host "wrote launcher: $LauncherPath" # Register / replace the scheduled task $TaskName = "CIS490-TrainerWorker" $existing = schtasks /Query /TN $TaskName 2>$null if ($existing) { Write-Host "removing existing scheduled task $TaskName" schtasks /Delete /TN $TaskName /F | Out-Null } # Run as the current user, at startup, restart if it stops, every 5 min check schtasks /Create /TN $TaskName /TR "`"$LauncherPath`"" /SC ONSTART /RU "$env:USERDOMAIN\$env:USERNAME" /RL HIGHEST /F | Out-Null # Add a second trigger that ensures the task is running every 5 minutes schtasks /Change /TN $TaskName /RI 5 /DU 9999:00 2>$null Write-Host "" Write-Host "scheduled task '$TaskName' created." Write-Host "Starting it now..." schtasks /Run /TN $TaskName | Out-Null Start-Sleep -Seconds 3 if (Test-Path $LogPath) { Write-Host "" Write-Host "=== first 30 log lines ===" Get-Content $LogPath -Tail 30 } Write-Host "" Write-Host "Done." Write-Host " Logs: Get-Content '$LogPath' -Wait" Write-Host " Status: schtasks /Query /TN $TaskName /V /FO LIST" Write-Host " Stop: schtasks /End /TN $TaskName" Write-Host " Remove: schtasks /Delete /TN $TaskName /F"