From 9496b537d61952abbe68800bea91dc3e4093e75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Wed, 7 Oct 2026 11:07:52 +0200 Subject: [PATCH] ci: download SQL Server media before installing Windows features (#2504) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 5.5 Signed-off-by: Jan-Otto Kröpke --- .github/workflows/ci.yml | 16 ++++++++++------ tools/setup-sql-server.ps1 | 32 ++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4fe4f06..f70c0167 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -355,6 +355,12 @@ jobs: key: sql-server-2025-express-fa7e1fabc9a2-${{ runner.os }} # Steps that do not register services run in the background while Windows features install. + - name: Download SQL Server media + id: download-mssql + background: true + shell: powershell + run: ./tools/setup-sql-server.ps1 -DownloadOnly + - name: Install FreeRDP client id: install-freerdp background: true @@ -528,6 +534,10 @@ jobs: ) Set-Content -Path $installer -Value $installerContent -Encoding utf8 + # Downloads stall once the DNS Server role is installed, so finish them first. + - name: Wait for downloads + wait: [download-mssql, install-freerdp, download-container-prereqs] + # Install every Windows feature in one foreground step. Steps that register # services, such as SQL Server setup, New-Cluster, and containerd, start only # afterwards: changing service configuration during the install aborts its @@ -617,9 +627,6 @@ jobs: Get-ClusterNode | Format-Table Name, State, NodeWeight, DynamicWeight Get-ClusterNetwork | Format-Table Name, State, Role, Address - - name: Wait for container prerequisites - wait: [download-container-prereqs] - - name: Prepare container runtime shell: pwsh run: | @@ -899,9 +906,6 @@ jobs: throw "Static pods did not reach Running state" } - - name: Wait for FreeRDP client - wait: [install-freerdp] - - parallel: - name: Setup local RDP session shell: powershell diff --git a/tools/setup-sql-server.ps1 b/tools/setup-sql-server.ps1 index 8a31b135..34e9503b 100644 --- a/tools/setup-sql-server.ps1 +++ b/tools/setup-sql-server.ps1 @@ -1,6 +1,22 @@ # Install a real Database Engine instance; LocalDB does not expose server counters. +# CI runs -DownloadOnly before installing the DNS Server role, which breaks +# downloads, and the installation after all Windows features are installed. +param([switch]$DownloadOnly) + $ErrorActionPreference = "Stop" +# Run an installer and fail instead of hanging when it does not finish in time. +function Invoke-Installer([string]$FilePath, [string[]]$ArgumentList, [int]$TimeoutMinutes) { + $process = Start-Process $FilePath -ArgumentList $ArgumentList -PassThru + # Windows PowerShell only reports ExitCode if the handle was read before exit. + $null = $process.Handle + if (-not $process.WaitForExit($TimeoutMinutes * 60 * 1000)) { + Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue + throw "$(Split-Path $FilePath -Leaf) did not finish within $TimeoutMinutes minutes" + } + return $process.ExitCode +} + $mediaDir = Join-Path $env:RUNNER_TEMP "sql-server" New-Item -ItemType Directory -Force -Path $mediaDir | Out-Null $setupDir = Join-Path $mediaDir "setup" @@ -18,20 +34,20 @@ if (-not (Test-Path (Join-Path $setupDir "setup.exe"))) { $media = Join-Path $mediaDir "SQLEXPR_x64_ENU.exe" foreach ($attempt in 1..3) { - $download = Start-Process $installer -Wait -PassThru ` + $exitCode = Invoke-Installer $installer -TimeoutMinutes 10 ` -ArgumentList "/ACTION=Download", "/MEDIATYPE=Core", "/QUIET", "/MEDIAPATH=$mediaDir" - if ($download.ExitCode -eq 0 -and (Test-Path $media)) { break } - if ($attempt -eq 3) { throw "SQL Server media download failed: $($download.ExitCode)" } - Write-Warning "SQL Server media download attempt $attempt failed: $($download.ExitCode)" + if ($exitCode -eq 0 -and (Test-Path $media)) { break } + if ($attempt -eq 3) { throw "SQL Server media download failed: $exitCode" } + Write-Warning "SQL Server media download attempt $attempt failed: $exitCode" Start-Sleep -Seconds 10 } - $extract = Start-Process $media -Wait -PassThru ` - -ArgumentList "/Q", "/X:$setupDir" - if ($extract.ExitCode -ne 0) { - throw "SQL Server media extraction failed: $($extract.ExitCode)" + $exitCode = Invoke-Installer $media -ArgumentList "/Q", "/X:$setupDir" -TimeoutMinutes 10 + if ($exitCode -ne 0) { + throw "SQL Server media extraction failed: $exitCode" } } +if ($DownloadOnly) { return } # Azure runners can expose sectors larger than SQL Server's supported 4 KB. # Keep every instance file on a disk with a known, compatible sector size.