diff --git a/apps/kubevirt-vms/ci1.yaml b/apps/kubevirt-vms/ci1.yaml new file mode 100644 index 0000000..a0ff135 --- /dev/null +++ b/apps/kubevirt-vms/ci1.yaml @@ -0,0 +1,352 @@ +# ============================================================================= +# ci1 — Windows Server 2025 KubeVirt VM (GitHub Actions Self-Hosted Runner) +# ============================================================================= +# Purpose: dedicated CI runner for FlowerCore.Updater Sandbox E2E nightly + +# future fleet WPF AAT lanes. Replaces the never-registered +# `bluejay-ws-sandbox-1` runner placeholder. Andrew explicitly does NOT want +# BLUEJAY-WS registered as a runner (workstation has personal/operator state). +# +# Status (2026-05-08): STAGED ONLY — DO NOT APPLY without operator review. +# See docs/infrastructure/windows-server-build-runner-plan.md "Phase 1 readiness gate". +# +# Prerequisites that MUST be satisfied first: +# 1. Windows Server 2025 ISO populated into the `windows-server-2025-iso` PVC +# (operator interactive step — Microsoft Evaluation Center download). +# 2. Either Multus + PROD VLAN NAD (preferred) OR pod-network only (this YAML). +# 3. KubeVirt CR feature gates: none required for non-persistent vTPM. +# +# Network choice in this draft: **pod-network fallback** (Calico default). +# Outbound-only is fine for the Updater Sandbox E2E runner workload (the runner +# polls GitHub Actions over HTTPS; no inbound listener needed). Switch to a +# Multus PROD VLAN NetworkAttachmentDefinition once Multus is installed and the +# operator wants L2 access from `ci1` to other PROD VLAN services. +# +# Sizing: 8 vCPU / 16 GB RAM / 200 GB disk on Longhorn (default storageClass). +# Capacity check 2026-05-08: each RKE2 node has 16 vCPU / ~64Gi allocatable; +# 8 vCPU is ~17% of one node's allocatable, fits comfortably. +# +# Apply (after operator approval + ISO loaded): +# kubectl --kubeconfig $env:USERPROFILE\.kube\rke2.yaml apply -f apps/kubevirt-vms/ci1.yaml +# +# Connect to console for Windows install: +# virtctl --kubeconfig $env:USERPROFILE\.kube\rke2.yaml vnc ci1 -n kubevirt-vms +# (Or via Guacamole once a connection profile is added.) +# ============================================================================= + +apiVersion: v1 +kind: Namespace +metadata: + name: kubevirt-vms + labels: + app.kubernetes.io/part-of: kubevirt-stack + pod-security.kubernetes.io/enforce: privileged + +--- +# ISO PVC — operator must populate this before applying the VM manifest. +# Population paths (see plan doc "Phase 1 readiness gate", section 2): +# Path A — manual upload via helper pod + kubectl cp +# Path B — install CDI, then DataVolume HTTP import +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: windows-server-2025-iso + namespace: kubevirt-vms +spec: + accessModes: + - ReadWriteOnce # Bump to ReadOnlyMany after population for multi-VM use + resources: + requests: + storage: 6Gi + storageClassName: longhorn + +--- +# Root disk PVC — empty 200Gi volume that Windows installs into. +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: ci1-rootdisk + namespace: kubevirt-vms +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 200Gi + storageClassName: longhorn + +--- +# Sysprep ConfigMap — autounattend.xml for hands-off Windows install. +# Sets local Administrator password (REPLACE the placeholder), enables RDP, +# enables WinRM, sets hostname, and configures static-ish networking via DHCP. +# The ISO + VirtIO drivers handle the rest. +apiVersion: v1 +kind: ConfigMap +metadata: + name: ci1-autounattend + namespace: kubevirt-vms +data: + autounattend.xml: | + + + + + + + + en-US + + en-US + en-US + en-US + en-US + + + + + + E:\amd64\2k25 + + + + + + + + 0 + true + + + 1 + 260 + EFI + + + 2 + 128 + MSR + + + 3 + true + Primary + + + + + 1 + 1 + FAT32 + + + + 2 + 2 + + + 3 + 3 + NTFS + + + + + + + + + + 0 + 3 + + + + + /IMAGE/INDEX + 2 + + + + + + + true + FlowerCore CI Runner + FlowerCore + + + + + + + + + CI1 + Central Standard Time + + + + false + + + + + + + + true + true + true + true + true + 3 + + + + + UABMAEEAQwBFAEgATwBMAEQARQBSAEEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIAUABhAHMAcwB3AG8AcgBkAA== + false</PlainText> + </AdministratorPassword> + </UserAccounts> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <Order>1</Order> + <CommandLine>powershell.exe -ExecutionPolicy Bypass -Command "Set-NetFirewallRule -DisplayGroup 'Remote Desktop' -Enabled True"</CommandLine> + <Description>Enable RDP firewall rule</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>2</Order> + <CommandLine>powershell.exe -ExecutionPolicy Bypass -Command "Enable-PSRemoting -Force; Set-Item WSMan:\localhost\Service\Auth\Basic $true; Set-Item WSMan:\localhost\Service\AllowUnencrypted $true"</CommandLine> + <Description>Enable WinRM (Phase 2 will pivot to HTTPS via step-ca cert)</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>3</Order> + <CommandLine>cmd.exe /c reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v EnableLUA /t REG_DWORD /d 0 /f</CommandLine> + <Description>Disable UAC (Phase 2 Puppet will re-evaluate)</Description> + </SynchronousCommand> + </FirstLogonCommands> + </component> + </settings> + </unattend> + +--- +# VirtualMachine — Windows Server 2025 CI runner. +apiVersion: kubevirt.io/v1 +kind: VirtualMachine +metadata: + name: ci1 + namespace: kubevirt-vms + labels: + app: ci-runner + role: github-actions-runner + flowercore.io/managed-by: bluejay-infra +spec: + running: false # Set to true after operator approves + ISO loaded + template: + metadata: + labels: + app: ci-runner + role: github-actions-runner + kubevirt.io/vm: ci1 + spec: + domain: + cpu: + cores: 8 + sockets: 1 + threads: 1 + memory: + guest: 16Gi + resources: + requests: + memory: 16Gi + limits: + memory: 16Gi + clock: + utc: {} + timer: + hpet: + present: false + pit: + tickPolicy: delay + rtc: + tickPolicy: catchup + hyperv: {} + features: + acpi: {} + apic: {} + hyperv: + relaxed: {} + vapic: {} + spinlocks: + spinlocks: 8191 + smm: {} + firmware: + bootloader: + efi: + secureBoot: true + devices: + tpm: {} # Non-persistent vTPM — sufficient for runner; no BitLocker + disks: + - name: rootdisk + bootOrder: 1 + disk: + bus: virtio + - name: windows-iso + bootOrder: 2 + cdrom: + bus: sata + - name: virtio-drivers + cdrom: + bus: sata + - name: sysprep + cdrom: + bus: sata + interfaces: + # Pod-network fallback for Phase 1. To switch to PROD VLAN once Multus + # + the prod-vlan57 NAD exist, replace this block with: + # - name: prod-net + # bridge: {} + # model: virtio + # and update the networks: stanza to use multus.networkName: kubevirt-vms/prod-vlan57 + - name: default + masquerade: {} + model: virtio + machine: + type: q35 + networks: + - name: default + pod: {} + volumes: + - name: rootdisk + persistentVolumeClaim: + claimName: ci1-rootdisk + - name: windows-iso + persistentVolumeClaim: + claimName: windows-server-2025-iso + - name: virtio-drivers + containerDisk: + image: quay.io/kubevirt/virtio-container-disk + - name: sysprep + sysprep: + configMap: + name: ci1-autounattend + terminationGracePeriodSeconds: 3600