From 21bbab7685514601fa93d37dc8f6bc32c8e605bf Mon Sep 17 00:00:00 2001 From: Dongruixuan Li Date: Sun, 1 Nov 2026 23:22:55 -0500 Subject: [PATCH 1/3] ci: cache compressed Windows image before installing Nix --- .github/workflows/go-test.yml | 24 +++++++++++++++++++----- e2e/windows/README.md | 7 +++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index a2a3241..d3e4f81 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -89,7 +89,20 @@ jobs: sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc sudo apt-get update sudo apt-get install -y --no-install-recommends qemu-system-x86 qemu-utils ovmf python3-venv unzip zstd + sudo chmod a+rw /dev/kvm + - name: Resolve Windows image revision + id: windows_image_revision + run: | + revision=$(git ls-remote https://github.com/starcatmeow/nylon-ci-windows-image.git refs/heads/main | cut -f1) + echo "revision=$revision" >> "$GITHUB_OUTPUT" + - name: Cache Windows image + id: windows_image_cache + uses: actions/cache@v4 + with: + path: ${{ runner.temp }}/windows.qcow2.zst + key: windows-image-zstd-${{ runner.os }}-${{ runner.arch }}-${{ steps.windows_image_revision.outputs.revision }} - uses: cachix/install-nix-action@v31 + if: steps.windows_image_cache.outputs.cache-hit != 'true' with: extra_nix_config: | extra-substituters = https://pub-b7e688bb852e422d84f49c2dce8e3461.r2.dev @@ -99,14 +112,15 @@ jobs: download-attempts = 1 extra-system-features = kvm - name: Build Windows image - id: windows_image + if: steps.windows_image_cache.outputs.cache-hit != 'true' run: | - nix build github:starcatmeow/nylon-ci-windows-image/main#nylon-ci-win2025 \ + nix build github:starcatmeow/nylon-ci-windows-image/${{ steps.windows_image_revision.outputs.revision }}#nylon-ci-win2025 \ --out-link "$RUNNER_TEMP/windows-image" --fallback - zstd -d "$RUNNER_TEMP/windows-image/nylon-ci-win2025.qcow2.zst" -o "$RUNNER_TEMP/windows.qcow2" - echo "qcow2=$RUNNER_TEMP/windows.qcow2" >> "$GITHUB_OUTPUT" + cp "$RUNNER_TEMP/windows-image/nylon-ci-win2025.qcow2.zst" "$RUNNER_TEMP/windows.qcow2.zst" + - name: Decompress Windows image + run: zstd -d "$RUNNER_TEMP/windows.qcow2.zst" -o "$RUNNER_TEMP/windows.qcow2" - name: Run Windows e2e - run: e2e/windows/run.sh '${{ steps.windows_image.outputs.qcow2 }}' + run: e2e/windows/run.sh "$RUNNER_TEMP/windows.qcow2" - name: Upload Windows e2e logs if: failure() uses: actions/upload-artifact@v4 diff --git a/e2e/windows/README.md b/e2e/windows/README.md index f9cd208..f57fd00 100644 --- a/e2e/windows/README.md +++ b/e2e/windows/README.md @@ -21,8 +21,11 @@ replies in both directions between the Windows nodes, and between win1 and Linux The Docker network and WinRM ports are fixed; run only one instance per host. Logs stay in `workdir/e2e/windows`; VMs, overlays, TAPs and containers are removed. -CI builds `github:starcatmeow/nylon-ci-windows-image/main#nylon-ci-win2025`, -decompresses its output, and passes the qcow2 path to the same script. +CI caches the zstd-compressed qcow2 with GitHub Actions, keyed by the image +repository's main revision. A cache hit skips installing Nix and building the +image. On a miss, CI builds `#nylon-ci-win2025` at that exact revision of +`github:starcatmeow/nylon-ci-windows-image`. Both paths decompress the cached +output and pass the qcow2 path to the same script. CI reads the public Nix cache at `https://pub-b7e688bb852e422d84f49c2dce8e3461.r2.dev`, trusting the `nylon-cache-1` public key configured in the workflow. Cache misses or download From 39754f1ba74690ede69c5d00deb8d9a02a0ad0e0 Mon Sep 17 00:00:00 2001 From: Dongruixuan Li Date: Mon, 2 Nov 2026 00:06:34 -0500 Subject: [PATCH 2/3] fix(e2e): run Windows Nylon tasks at normal priority --- e2e/windows/connectivity.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/e2e/windows/connectivity.py b/e2e/windows/connectivity.py index aa50ecd..698f761 100644 --- a/e2e/windows/connectivity.py +++ b/e2e/windows/connectivity.py @@ -146,12 +146,15 @@ def test_connectivity(self): # SYSTEM provides UAPI privileges and the scheduled task survives closing WinRM. $action = New-ScheduledTaskAction -Execute 'C:\\nylon-e2e\\nylon.exe' -WorkingDirectory 'C:\\nylon-e2e' -Argument 'run -v -w --config central.json --node {name}.json' $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest -Register-ScheduledTask -TaskName 'nylon-e2e' -Action $action -Principal $principal | Out-Null +# Task Scheduler defaults to background priority; Nylon must keep up with probes. +$settings = New-ScheduledTaskSettingsSet -Priority 4 +Register-ScheduledTask -TaskName 'nylon-e2e' -Action $action -Principal $principal -Settings $settings | Out-Null Start-ScheduledTask -TaskName 'nylon-e2e' """) def collect_logs(): - (WORK / "linux.log").write_text(run("docker", "logs", LINUX)) + logs = subprocess.run(["docker", "logs", LINUX], check=True, capture_output=True, text=True) + (WORK / "linux.log").write_text(logs.stdout + logs.stderr) for name, port in ports.items(): try: (WORK / name / "nylon.log").write_text(powershell(port, From e894a3893664ecffcb30339a9a3eeb7cd646e064 Mon Sep 17 00:00:00 2001 From: Dongruixuan Li Date: Mon, 2 Nov 2026 00:17:54 -0500 Subject: [PATCH 3/3] fix(e2e): retain WinRM profile hives and save built images early --- .github/workflows/go-test.yml | 10 ++++++++-- e2e/windows/connectivity.py | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index d3e4f81..6afcc43 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -95,9 +95,9 @@ jobs: run: | revision=$(git ls-remote https://github.com/starcatmeow/nylon-ci-windows-image.git refs/heads/main | cut -f1) echo "revision=$revision" >> "$GITHUB_OUTPUT" - - name: Cache Windows image + - name: Restore Windows image id: windows_image_cache - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: ${{ runner.temp }}/windows.qcow2.zst key: windows-image-zstd-${{ runner.os }}-${{ runner.arch }}-${{ steps.windows_image_revision.outputs.revision }} @@ -117,6 +117,12 @@ jobs: nix build github:starcatmeow/nylon-ci-windows-image/${{ steps.windows_image_revision.outputs.revision }}#nylon-ci-win2025 \ --out-link "$RUNNER_TEMP/windows-image" --fallback cp "$RUNNER_TEMP/windows-image/nylon-ci-win2025.qcow2.zst" "$RUNNER_TEMP/windows.qcow2.zst" + - name: Save Windows image + if: steps.windows_image_cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ${{ runner.temp }}/windows.qcow2.zst + key: ${{ steps.windows_image_cache.outputs.cache-primary-key }} - name: Decompress Windows image run: zstd -d "$RUNNER_TEMP/windows.qcow2.zst" -o "$RUNNER_TEMP/windows.qcow2" - name: Run Windows e2e diff --git a/e2e/windows/connectivity.py b/e2e/windows/connectivity.py index 698f761..ae299a2 100644 --- a/e2e/windows/connectivity.py +++ b/e2e/windows/connectivity.py @@ -94,6 +94,10 @@ def configure(): if process.poll() is not None: self.fail(f"{name} QEMU exited; see {directory / 'qemu.log'}") return powershell(port, f""" +# WinRM shells share profile handles; don't unload the hive while another still uses it. +$policy = 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\System' +New-Item -Path $policy -Force | Out-Null +New-ItemProperty -Path $policy -Name DisableForceUnload -PropertyType DWord -Value 1 -Force | Out-Null $adapter = Get-NetAdapter | Where-Object {{ $_.MacAddress -eq '52-54-00-00-00-0{index}' }} Set-NetIPInterface -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 -Dhcp Disabled Get-NetIPAddress -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | Remove-NetIPAddress -Confirm:$false