|
| 1 | +# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved. |
| 2 | +# SPDX-License-Identifier: MIT |
| 3 | + |
| 4 | +# Manual-only maintenance workflow for the self-hosted AMD (Strix) CI runner. |
| 5 | +# |
| 6 | +# Why this exists: the runner's AMD Vulkan stack intermittently enters a |
| 7 | +# multi-minute window where the MoE embedding model aborts llama-server |
| 8 | +# startup ("llama-server failed to start"), failing the embedder-loading CI |
| 9 | +# checks (Test Lemonade Embeddings API, RAG Integration). Upstream: |
| 10 | +# llama.cpp #16301 / lemonade #612. A newer GPU driver may close or shorten |
| 11 | +# that window. This workflow lets a maintainer update the driver remotely. |
| 12 | +# |
| 13 | +# It NEVER runs automatically -- workflow_dispatch only. Default action is |
| 14 | +# "check-only" (report current + available driver, change nothing). Installing |
| 15 | +# and/or rebooting must be explicitly selected at dispatch time. |
| 16 | +# |
| 17 | +# NOTE: a forced reboot under "update-and-reboot" takes the runner offline. The |
| 18 | +# runner reconnects after boot only if the GitHub Actions runner is registered |
| 19 | +# as a Windows service (auto-start). If it runs interactively, someone must |
| 20 | +# restart it by hand. The dispatched job itself may report as failed/cancelled |
| 21 | +# once the box reboots -- that is expected, not a real failure. |
| 22 | + |
| 23 | +name: STX Driver Update (manual) |
| 24 | + |
| 25 | +on: |
| 26 | + workflow_dispatch: |
| 27 | + inputs: |
| 28 | + runner_label: |
| 29 | + description: 'Self-hosted runner label to target' |
| 30 | + type: choice |
| 31 | + options: |
| 32 | + - stx |
| 33 | + - stx-test |
| 34 | + default: stx |
| 35 | + action: |
| 36 | + description: 'What to do on the runner' |
| 37 | + type: choice |
| 38 | + options: |
| 39 | + - check-only # report current + available driver, change nothing |
| 40 | + - update # install matching driver update(s), no reboot |
| 41 | + - update-and-reboot # install, then force-restart the machine |
| 42 | + default: check-only |
| 43 | + driver_filter: |
| 44 | + description: 'Regex matched against update titles to pick the GPU driver' |
| 45 | + type: string |
| 46 | + default: 'AMD|Radeon|Display' |
| 47 | + |
| 48 | +concurrency: |
| 49 | + group: stx-driver-update |
| 50 | + cancel-in-progress: false |
| 51 | + |
| 52 | +permissions: |
| 53 | + contents: read |
| 54 | + |
| 55 | +jobs: |
| 56 | + driver-update: |
| 57 | + name: Driver update (${{ inputs.action }}) |
| 58 | + runs-on: ${{ inputs.runner_label }} |
| 59 | + timeout-minutes: 60 |
| 60 | + env: |
| 61 | + ACTION: ${{ inputs.action }} |
| 62 | + DRIVER_FILTER: ${{ inputs.driver_filter }} |
| 63 | + |
| 64 | + steps: |
| 65 | + - name: Report current GPU driver |
| 66 | + shell: powershell |
| 67 | + run: | |
| 68 | + $ErrorActionPreference = "Stop" |
| 69 | + Write-Host "=== Current display adapters / drivers ===" |
| 70 | + Get-CimInstance Win32_VideoController | |
| 71 | + Select-Object Name, DriverVersion, DriverDate, Status, PNPDeviceID | |
| 72 | + Format-List |
| 73 | + Write-Host "=== OS / build ===" |
| 74 | + Get-CimInstance Win32_OperatingSystem | |
| 75 | + Select-Object Caption, Version, BuildNumber, LastBootUpTime | |
| 76 | + Format-List |
| 77 | +
|
| 78 | + - name: Check privileges |
| 79 | + shell: powershell |
| 80 | + run: | |
| 81 | + $ErrorActionPreference = "Stop" |
| 82 | + $id = [Security.Principal.WindowsIdentity]::GetCurrent() |
| 83 | + $principal = New-Object Security.Principal.WindowsPrincipal($id) |
| 84 | + $isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) |
| 85 | + Write-Host "Running as: $($id.Name) (admin=$isAdmin)" |
| 86 | + if (-not $isAdmin -and $env:ACTION -ne "check-only") { |
| 87 | + Write-Host "[ERROR] Driver install/reboot requires Administrator." |
| 88 | + Write-Host " What to do: run the GitHub Actions runner service as an" |
| 89 | + Write-Host " administrator (or LocalSystem) on this machine, or perform the" |
| 90 | + Write-Host " driver update manually via AMD Adrenalin on the box." |
| 91 | + throw "Insufficient privileges for action '$($env:ACTION)'" |
| 92 | + } |
| 93 | +
|
| 94 | + - name: Search and optionally install driver updates |
| 95 | + shell: powershell |
| 96 | + run: | |
| 97 | + $ErrorActionPreference = "Stop" |
| 98 | + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 |
| 99 | + $filter = $env:DRIVER_FILTER |
| 100 | + Write-Host "Driver title filter: '$filter'" |
| 101 | +
|
| 102 | + # Use the native Windows Update COM API (no third-party module). |
| 103 | + $session = New-Object -ComObject Microsoft.Update.Session |
| 104 | + $searcher = $session.CreateUpdateSearcher() |
| 105 | +
|
| 106 | + # Include the Microsoft Update service so optional third-party (AMD) |
| 107 | + # driver updates are visible, not just the default WU catalog. |
| 108 | + $muServiceId = "7971f918-a847-4430-9279-4a52d1efe18d" |
| 109 | + try { |
| 110 | + $mgr = New-Object -ComObject Microsoft.Update.ServiceManager |
| 111 | + $mgr.AddService2($muServiceId, 7, "") | Out-Null |
| 112 | + $searcher.ServerSelection = 3 # ssOthers |
| 113 | + $searcher.ServiceID = $muServiceId |
| 114 | + Write-Host "Querying Microsoft Update for driver-class updates..." |
| 115 | + } catch { |
| 116 | + Write-Host "[WARN] Could not register Microsoft Update service: $($_.Exception.Message)" |
| 117 | + Write-Host "Falling back to the default Windows Update catalog." |
| 118 | + } |
| 119 | +
|
| 120 | + $result = $searcher.Search("IsInstalled=0 and Type='Driver'") |
| 121 | + $all = @($result.Updates) |
| 122 | + Write-Host "Driver-class updates offered: $($all.Count)" |
| 123 | + foreach ($u in $all) { Write-Host " - $($u.Title)" } |
| 124 | +
|
| 125 | + $matched = @($all | Where-Object { $_.Title -match $filter }) |
| 126 | + Write-Host "Updates matching filter '$filter': $($matched.Count)" |
| 127 | + foreach ($u in $matched) { Write-Host " * $($u.Title)" } |
| 128 | +
|
| 129 | + if ($matched.Count -eq 0) { |
| 130 | + Write-Host "No newer matching driver available -- nothing to install." |
| 131 | + exit 0 |
| 132 | + } |
| 133 | +
|
| 134 | + if ($env:ACTION -eq "check-only") { |
| 135 | + Write-Host "check-only: a newer matching driver IS available but will NOT be installed." |
| 136 | + exit 0 |
| 137 | + } |
| 138 | +
|
| 139 | + # Accept EULAs and collect into an update collection. |
| 140 | + $toInstall = New-Object -ComObject Microsoft.Update.UpdateColl |
| 141 | + foreach ($u in $matched) { |
| 142 | + if (-not $u.EulaAccepted) { $u.AcceptEula() } |
| 143 | + $toInstall.Add($u) | Out-Null |
| 144 | + } |
| 145 | +
|
| 146 | + Write-Host "Downloading $($toInstall.Count) driver update(s)..." |
| 147 | + $downloader = $session.CreateUpdateDownloader() |
| 148 | + $downloader.Updates = $toInstall |
| 149 | + $dl = $downloader.Download() |
| 150 | + Write-Host "Download result code: $($dl.ResultCode) (2 = succeeded)" |
| 151 | + if ($dl.ResultCode -ne 2) { |
| 152 | + throw "Driver download failed with result code $($dl.ResultCode)" |
| 153 | + } |
| 154 | +
|
| 155 | + Write-Host "Installing driver update(s)..." |
| 156 | + $installer = $session.CreateUpdateInstaller() |
| 157 | + $installer.Updates = $toInstall |
| 158 | + $inst = $installer.Install() |
| 159 | + Write-Host "Install result code: $($inst.ResultCode) (2 = succeeded)" |
| 160 | + Write-Host "Reboot required by installer: $($inst.RebootRequired)" |
| 161 | + if ($inst.ResultCode -ne 2) { |
| 162 | + throw "Driver install failed with result code $($inst.ResultCode)" |
| 163 | + } |
| 164 | +
|
| 165 | + Write-Host "=== Driver after install ===" |
| 166 | + Get-CimInstance Win32_VideoController | |
| 167 | + Select-Object Name, DriverVersion, DriverDate | Format-List |
| 168 | +
|
| 169 | + - name: Force restart runner |
| 170 | + if: ${{ inputs.action == 'update-and-reboot' }} |
| 171 | + shell: powershell |
| 172 | + run: | |
| 173 | + $ErrorActionPreference = "Stop" |
| 174 | + Write-Host "Scheduling forced restart in 30 seconds so this job can report first." |
| 175 | + Write-Host "The runner will reconnect after boot only if it runs as an auto-start service." |
| 176 | + # /r restart, /t delay, /f force-close apps, /c comment |
| 177 | + shutdown /r /t 30 /f /c "GAIA CI: AMD driver-update reboot" |
| 178 | + Write-Host "Restart scheduled." |
0 commit comments