-
Notifications
You must be signed in to change notification settings - Fork 2
feat: convert to packer template #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| output/ | ||
| output-*/ | ||
| efivars.fd | ||
| packer_cache/ | ||
| crash.log | ||
| *.auto.pkrvars.hcl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| # Packer template for Oxide Windows images | ||
|
|
||
| This directory contains a [Packer](https://developer.hashicorp.com/packer) | ||
| template that builds a generalized Windows Server image suitable for import | ||
| into an Oxide rack. It is the successor to the `wimsy` Rust tool in this | ||
| repository and reproduces its build flow: | ||
|
|
||
| 1. Create a blank raw disk and boot Windows Setup in a QEMU/KVM guest that | ||
| matches what an Oxide rack presents: an NVMe boot disk (512-byte sectors) | ||
| and a virtio-net NIC. | ||
| 2. Drive an unattended installation via a rendered `Autounattend.xml` | ||
| (delivered on a virtual floppy), staging the virtio NetKVM/viostor drivers | ||
| from the driver ISO during the `offlineServicing` pass. | ||
| 3. Provision over WinRM: enable the EMS serial console, ping, and RDP; | ||
| install OpenSSH and the Oxide fork of cloudbase-init; run disk cleanup and | ||
| shrink the OS partition. | ||
| 4. De-provision (reset WinRM to defaults, remove autologon credentials, | ||
| scramble the build password) and generalize with sysprep, which disables | ||
| the Administrator account on first boot and hands configuration over to | ||
| cloudbase-init. | ||
| 5. Trim the raw image down to the end of the OS partition, rebuild the | ||
| secondary GPT, and sparsify. The result is `output/windows-server.raw` | ||
| plus a `.sha256` checksum ready for `oxide disk import`. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| The build must run on a Linux host with KVM. Required tools: | ||
|
|
||
| * `packer` (>= 1.10) with the QEMU plugin (installed by `packer init`, | ||
| which `build.sh` runs for you) | ||
| * `qemu-system-x86_64` and `qemu-img` | ||
| * `sgdisk` (from `gdisk`) to trim the output image | ||
| * OVMF UEFI firmware (`edk2-ovmf` / `ovmf` package) | ||
|
|
||
| You also need: | ||
|
|
||
| * A Windows Server ISO (2016/2019/2022/2025). See the repository README for | ||
| ISO requirements. | ||
| * A virtio driver ISO using the Fedora directory layout | ||
| (`NetKVM/<version>/amd64`, `viostor/<version>/amd64`), e.g. | ||
| [virtio-win.iso](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/). | ||
|
|
||
| The guest needs outbound Internet access (Packer's user-mode networking) to | ||
| download OpenSSH and cloudbase-init. | ||
|
|
||
| ## Usage | ||
|
|
||
| ```sh | ||
| ./build.sh \ | ||
| -var windows_iso_path=/path/to/windows_server_2022.iso \ | ||
| -var virtio_iso_path=/path/to/virtio-win.iso | ||
| ``` | ||
|
|
||
| Commonly overridden variables (see [variables.pkr.hcl](variables.pkr.hcl) for | ||
| the full list): | ||
|
|
||
| | Variable | Default | Purpose | | ||
| | --- | --- | --- | | ||
| | `windows_iso_path` | (required) | Windows Server installation ISO | | ||
| | `virtio_iso_path` | (required) | virtio driver ISO | | ||
| | `windows_iso_checksum` | `none` | ISO checksum verification (`sha256:...`) | | ||
| | `windows_version` | `2k22` | virtio driver directory (`2k16`/`2k19`/`2k22`/`2k25`) | | ||
| | `image_index` | `2` | Windows edition index in the ISO | | ||
| | `ovmf_code_path` / `ovmf_vars_path` | Arch paths | OVMF firmware location | | ||
| | `headless` | `true` | Set `false` to watch the installer | | ||
| | `winrm_password` | `Packer!build0` | Build-time Administrator password (scrambled before capture) | | ||
|
|
||
| To debug a failing build, pass `-var headless=false` to watch the console, | ||
| and add `-on-error=ask` to keep the VM around on failure. EMS serial output | ||
| is forwarded to Packer's stdout during the build. | ||
|
|
||
| ## Notes and differences from wimsy | ||
|
|
||
| * The final image contains no build credentials or build machinery: the | ||
| Administrator password is scrambled, autologon/WinRM build settings are | ||
| reset, and the sysprep scheduled task and provisioner temp files are | ||
| removed by [scripts/sysprep.ps1](scripts/sysprep.ps1) before sysprep runs. | ||
| A `C:\Users\Administrator` profile folder exists in the image, as it did | ||
| in wimsy-built images (wimsy's audit-mode session signed in as | ||
| Administrator too); the account itself is disabled on first boot in both | ||
| flows. | ||
| * The unattend collateral in [../unattend](../unattend) (`specialize-unattend.xml`, | ||
| cloudbase-init configs) is shared with wimsy and delivered on the build | ||
| floppy. | ||
| * Building images on illumos hosts (wimsy's `build-installation-disk` / | ||
| Propolis flow) is not supported by this template; use wimsy for that. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <unattend xmlns="urn:schemas-microsoft-com:unattend"> | ||
| <settings pass="windowsPE"> | ||
| <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" | ||
| xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <SetupUILanguage> | ||
| <UILanguage>en-US</UILanguage> | ||
| </SetupUILanguage> | ||
| <InputLocale>en-US</InputLocale> | ||
| <SystemLocale>en-US</SystemLocale> | ||
| <UILanguage>en-US</UILanguage> | ||
| <UserLocale>en-US</UserLocale> | ||
| </component> | ||
| <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" | ||
| xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <DiskConfiguration> | ||
| <Disk wcm:action="add"> | ||
| <CreatePartitions> | ||
| <CreatePartition wcm:action="add"> | ||
| <Order>1</Order> | ||
| <Size>500</Size> | ||
| <Type>Primary</Type> | ||
| </CreatePartition> | ||
| <CreatePartition wcm:action="add"> | ||
| <Order>2</Order> | ||
| <Size>100</Size> | ||
| <Type>EFI</Type> | ||
| </CreatePartition> | ||
| <CreatePartition wcm:action="add"> | ||
| <Order>3</Order> | ||
| <Size>128</Size> | ||
| <Type>MSR</Type> | ||
| </CreatePartition> | ||
| <CreatePartition wcm:action="add"> | ||
| <Order>4</Order> | ||
| <Extend>true</Extend> | ||
| <Type>Primary</Type> | ||
| </CreatePartition> | ||
| </CreatePartitions> | ||
| <ModifyPartitions> | ||
| <ModifyPartition wcm:action="add"> | ||
| <Order>1</Order> | ||
| <PartitionID>1</PartitionID> | ||
| <Format>NTFS</Format> | ||
| <Label>Recovery</Label> | ||
| <TypeID>DE94BBA4-06D1-4D40-A16A-BFD50179D6AC</TypeID> | ||
| </ModifyPartition> | ||
| <ModifyPartition wcm:action="add"> | ||
| <Order>2</Order> | ||
| <PartitionID>2</PartitionID> | ||
| <Format>FAT32</Format> | ||
| <Label>System</Label> | ||
| </ModifyPartition> | ||
| <ModifyPartition wcm:action="add"> | ||
| <Order>3</Order> | ||
| <PartitionID>3</PartitionID> | ||
| </ModifyPartition> | ||
| <ModifyPartition wcm:action="add"> | ||
| <Order>4</Order> | ||
| <PartitionID>4</PartitionID> | ||
| <Format>NTFS</Format> | ||
| <Letter>C</Letter> | ||
| <Label>OS</Label> | ||
| </ModifyPartition> | ||
| </ModifyPartitions> | ||
| <DiskID>0</DiskID> | ||
| <WillWipeDisk>true</WillWipeDisk> | ||
| </Disk> | ||
| </DiskConfiguration> | ||
| <ImageInstall> | ||
| <OSImage> | ||
| <InstallFrom> | ||
| <MetaData wcm:action="add"> | ||
| <Key>/IMAGE/INDEX</Key> | ||
| <Value>${image_index}</Value> | ||
| </MetaData> | ||
| </InstallFrom> | ||
| <InstallTo> | ||
| <DiskID>0</DiskID> | ||
| <PartitionID>4</PartitionID> | ||
| </InstallTo> | ||
| </OSImage> | ||
| </ImageInstall> | ||
| <UserData> | ||
| <AcceptEula>true</AcceptEula> | ||
| <ProductKey> | ||
| <WillShowUI>Never</WillShowUI> | ||
| </ProductKey> | ||
| </UserData> | ||
| </component> | ||
| </settings> | ||
| <settings pass="offlineServicing"> | ||
| <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" | ||
| xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <DriverPaths> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="1"> | ||
| <Path>D:\NetKVM\${windows_version}\amd64</Path> | ||
| </PathAndCredentials> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="2"> | ||
| <Path>D:\viostor\${windows_version}\amd64</Path> | ||
| </PathAndCredentials> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="3"> | ||
| <Path>E:\NetKVM\${windows_version}\amd64</Path> | ||
| </PathAndCredentials> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="4"> | ||
| <Path>E:\viostor\${windows_version}\amd64</Path> | ||
| </PathAndCredentials> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="5"> | ||
| <Path>F:\NetKVM\${windows_version}\amd64</Path> | ||
| </PathAndCredentials> | ||
| <PathAndCredentials wcm:action="add" wcm:keyValue="6"> | ||
| <Path>F:\viostor\${windows_version}\amd64</Path> | ||
| </PathAndCredentials> | ||
| </DriverPaths> | ||
| </component> | ||
| </settings> | ||
| <settings pass="specialize"> | ||
| <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" | ||
| xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <ComputerName>*</ComputerName> | ||
| </component> | ||
| </settings> | ||
| <settings pass="oobeSystem"> | ||
| <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" | ||
| xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <InputLocale>en-US</InputLocale> | ||
| <SystemLocale>en-US</SystemLocale> | ||
| <UILanguage>en-US</UILanguage> | ||
| <UserLocale>en-US</UserLocale> | ||
| </component> | ||
| <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" | ||
| xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | ||
| <OOBE> | ||
| <HideEULAPage>true</HideEULAPage> | ||
| <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> | ||
| <HideOnlineAccountScreens>true</HideOnlineAccountScreens> | ||
| <HideLocalAccountScreen>true</HideLocalAccountScreen> | ||
| <NetworkLocation>Work</NetworkLocation> | ||
| <ProtectYourPC>1</ProtectYourPC> | ||
| </OOBE> | ||
| <UserAccounts> | ||
| <AdministratorPassword> | ||
| <Value>${admin_password}</Value> | ||
| <PlainText>true</PlainText> | ||
| </AdministratorPassword> | ||
| </UserAccounts> | ||
| <AutoLogon> | ||
| <Password> | ||
| <Value>${admin_password}</Value> | ||
| <PlainText>true</PlainText> | ||
| </Password> | ||
| <Enabled>true</Enabled> | ||
| <LogonCount>1</LogonCount> | ||
| <Username>Administrator</Username> | ||
| </AutoLogon> | ||
| <FirstLogonCommands> | ||
| <SynchronousCommand wcm:action="add"> | ||
| <CommandLine>cmd /c powershell.exe -NoProfile -ExecutionPolicy Bypass -File A:\setup-winrm.ps1</CommandLine> | ||
| <Order>1</Order> | ||
| <Description>Configure WinRM for Packer provisioning</Description> | ||
| </SynchronousCommand> | ||
| </FirstLogonCommands> | ||
| </component> | ||
| </settings> | ||
| </unattend> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| cd "$SCRIPT_DIR" | ||
|
|
||
| packer init . | ||
|
|
||
| # Forward all arguments to packer build. | ||
| exec packer build "$@" . |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| $ErrorActionPreference = 'Stop' | ||
|
|
||
| function RetryWithBackoff { | ||
| param ( | ||
| [Parameter(Mandatory=$True)] | ||
| [scriptblock]$ScriptBlock, | ||
|
|
||
| [Parameter(Mandatory=$False)] | ||
| [int]$MaxAttempts = 5, | ||
|
|
||
| [Parameter(Mandatory=$False)] | ||
| [int]$InitialBackoffDelayMs = 1000, | ||
|
|
||
| [Parameter(Mandatory=$False)] | ||
| [int]$MaxBackoffDelayMs = 30000 | ||
| ) | ||
|
|
||
| $cmd = $ScriptBlock.ToString() | ||
| $cnt = 0 | ||
| $delay = $InitialBackoffDelayMs | ||
| do { | ||
| $cnt++ | ||
| try { | ||
| Invoke-Command -Command $ScriptBlock | ||
| return | ||
| } catch { | ||
| Write-Host "Command $cmd failed, will retry after $delay ms; error: " $_.Exception.InnerException.Message | ||
| Start-Sleep -Milliseconds $delay | ||
| $delay = [math]::Min($delay * 2, $MaxBackoffDelayMs) | ||
| } | ||
| } while ($cnt -lt $MaxAttempts) | ||
|
|
||
| Write-Error -Message "Command $cmd failed after $MaxAttempts attempts" -ErrorAction Stop | ||
| } | ||
|
|
||
| Write-Host "Installing cloudbase-init" | ||
| RetryWithBackoff -ScriptBlock { Invoke-WebRequest -Uri https://oxide-omicron-build.s3.amazonaws.com/CloudbaseInitSetup.msi -OutFile C:\Windows\Temp\CloudbaseInitSetup.msi | Out-Null } | ||
| Start-Process msiexec.exe -ArgumentList "/i C:\Windows\Temp\CloudbaseInitSetup.msi /qn /norestart RUN_SERVICE_AS_LOCAL_SYSTEM=1" -Wait | ||
| Remove-Item C:\Windows\Temp\CloudbaseInitSetup.msi | ||
|
|
||
| # Copy cloudbase-init configuration from the floppy drive (A:\). | ||
| $confPath = "C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\" | ||
| Copy-Item "A:\cloudbase-init.conf" -Destination "$confPath\cloudbase-init.conf" | ||
| Copy-Item "A:\cloudbase-init-unattend.conf" -Destination "$confPath\cloudbase-init-unattend.conf" | ||
| Remove-Item "$confPath\Unattend.xml" | ||
|
|
||
| # Disable the service so it doesn't run on first boot and contend with the | ||
| # unattend first pass. Re-enabled during the specialize phase. | ||
| Set-Service -Name cloudbase-init -StartupType Disabled |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's how I ran this. Just noting this for future me to document it.
Download the virtio ISO.
Download the Windows Server 2022 ISO: https://go.microsoft.com/fwlink/p/?linkid=2195686&clcid=0x409&culture=en-us&country=us
Run Packer.