diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f70c0167..2e121e66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -388,10 +388,7 @@ jobs: $vhd = Join-Path $env:RUNNER_TEMP "$Name.vhdx" New-VHD -Path $vhd -Dynamic -SizeBytes 512MB | Out-Null $volume = Invoke-WithVhdLock { - Mount-VHD $vhd -PassThru | Get-Disk | - Initialize-Disk -PartitionStyle GPT -PassThru | - New-Partition -UseMaximumSize -AssignDriveLetter | - Format-Volume -FileSystem NTFS -NewFileSystemLabel $Name -Confirm:$false + Format-NewDisk (Mount-VHD $vhd -PassThru | Get-Disk) $Name } $mountPoint = "$($volume.DriveLetter):" @@ -1085,7 +1082,7 @@ jobs: Select-Object -ExpandProperty Paths - name: Enable Windows Update - timeout-minutes: 5 + timeout-minutes: 8 shell: powershell run: | $ErrorActionPreference = "Stop" @@ -1107,13 +1104,49 @@ jobs: # Searching only retrieves metadata, without installing updates. try { $result = $searcher.Search("IsInstalled=0 and IsHidden=0") + $pendingCount = $result.Updates.Count } catch { Write-Warning "Offline catalog search failed: $($_.Exception.ToString())" - $searcher.Online = $true - $result = $searcher.Search("IsInstalled=0 and IsHidden=0") + + # The online search usually finishes in under 30 seconds but + # occasionally stalls for minutes. The COM call cannot be + # cancelled, so run it in a job and restart the service on stall. + $onlineSearch = { + $ErrorActionPreference = "Stop" + $session = New-Object -ComObject Microsoft.Update.Session + $session.ClientApplicationID = "windows_exporter-ci" + $searcher = $session.CreateUpdateSearcher() + $searcher.Online = $true + $searcher.Search("IsInstalled=0 and IsHidden=0").Updates.Count + } + + $pendingCount = $null + for ($attempt = 1; $attempt -le 3; $attempt++) { + $job = Start-Job -ScriptBlock $onlineSearch + if (Wait-Job $job -Timeout 90) { + try { + $pendingCount = Receive-Job $job + break + } + catch { + Write-Warning "Online catalog search attempt $attempt failed: $($_.Exception.Message)" + } + } + else { + Write-Warning "Online catalog search attempt $attempt timed out" + Stop-Job $job + Restart-Service wuauserv -Force + (Get-Service wuauserv).WaitForStatus("Running", [TimeSpan]::FromSeconds(30)) + } + Remove-Job $job -Force + } + + if ($null -eq $pendingCount) { + throw "Online catalog search failed after $($attempt - 1) attempts" + } } - Write-Host "Windows Update catalog contains $($result.Updates.Count) pending updates" + Write-Host "Windows Update catalog contains $pendingCount pending updates" Get-Service wuauserv | Format-Table Name, Status, StartType diff --git a/tools/setup-sql-server.ps1 b/tools/setup-sql-server.ps1 index 34e9503b..fb025883 100644 --- a/tools/setup-sql-server.ps1 +++ b/tools/setup-sql-server.ps1 @@ -61,9 +61,7 @@ $volume = Invoke-WithVhdLock { if ($disk.PhysicalSectorSize -gt 4096) { throw "SQL Server fixture disk exposes unsupported physical sectors" } - $disk | Initialize-Disk -PartitionStyle GPT -PassThru | - New-Partition -UseMaximumSize -AssignDriveLetter | - Format-Volume -FileSystem NTFS -NewFileSystemLabel CISQL -Confirm:$false + Format-NewDisk $disk CISQL } $instanceDir = "$($volume.DriveLetter):\SQLServer" fsutil.exe fsinfo sectorinfo "$($volume.DriveLetter):" diff --git a/tools/vhd-lock.ps1 b/tools/vhd-lock.ps1 index 43bf7823..6964ce1e 100644 --- a/tools/vhd-lock.ps1 +++ b/tools/vhd-lock.ps1 @@ -18,3 +18,22 @@ function Invoke-WithVhdLock([scriptblock]$ScriptBlock) { $mutex.Dispose() } } + +# New-Partition can return before the storage provider exposes the new volume, +# which makes Format-Volume fail with CmdletizationQuery_NotFound. Retry until +# the volume appears. +function Format-NewDisk($Disk, [string]$Label) { + $partition = $Disk | Initialize-Disk -PartitionStyle GPT -PassThru | + New-Partition -UseMaximumSize -AssignDriveLetter + $deadline = (Get-Date).AddSeconds(30) + while ($true) { + try { + return $partition | Format-Volume -FileSystem NTFS -NewFileSystemLabel $Label -Confirm:$false + } catch { + if ($_.FullyQualifiedErrorId -notlike "CmdletizationQuery_NotFound*" -or (Get-Date) -ge $deadline) { + throw + } + Start-Sleep -Seconds 1 + } + } +}