diff --git a/Config.psm1 b/Config.psm1 index 8317b51..05290c7 100644 --- a/Config.psm1 +++ b/Config.psm1 @@ -31,12 +31,14 @@ function Get-AvailableConfigOptions { @{"Name" = "virtual_disk_format"; "DefaultValue" = "VHDX"; "Description" = "Select between VHD, VHDX, QCOW2, VMDK or RAW formats."}, @{"Name" = "image_type"; "DefaultValue" = "HYPER-V"; - "Description" = "This parameter allows to choose between MAAS, KVM, VMware and Hyper-V specific images. + "Description" = "This parameter allows to choose between MAAS, KVM, Nutanix, VMware and Hyper-V specific images. For HYPER-V, cloudbase-init will be installed and the generated image should be in vhd or vhdx format. For MAAS, in addition to cloudbase-init, the curtin tools are installed and the generated image should be in raw.tgz format. For KVM, in addition to cloudbase-init, the VirtIO drivers are installed - and the generated image should be in qcow2 format."}, + and the generated image should be in qcow2 format. + For Nutanix, in addition to cloudbase-init, the Nutanix VirtIO drivers + are installed and the generated image should be in qcow2 format."}, @{"Name" = "disk_layout"; "DefaultValue" = "BIOS"; "Description" = "This parameter can be set to either BIOS or UEFI."}, @{"Name" = "product_key"; @@ -108,10 +110,12 @@ function Get-AvailableConfigOptions { @{"Name" = "shrink_image_to_minimum_size"; "DefaultValue" = $true; "AsBoolean" = $true "Description" = "Whether to shrink the image partition and disk after the image generation is complete."}, @{"Name" = "virtio_iso_path"; "GroupName" = "drivers"; - "Description" = "The path to the ISO file containing the VirtIO drivers."}, + "Description" = "The path to the ISO file containing the VirtIO drivers. + For Nutanix images, virtio_iso_path must point to the Nutanix VirtIO drivers ISO."}, @{"Name" = "virtio_base_path"; "GroupName" = "drivers"; "Description" = "The location where the VirtIO drivers are found. - For example, the location of a mounted VirtIO ISO. VirtIO versions supported >=0.1.6.x"}, + For example, the location of a mounted VirtIO ISO. VirtIO versions supported >=0.1.6.x + For Nutanix images, virtio_base_path must point to the Nutanix VirtIO drivers."}, @{"Name" = "install_qemu_ga"; "GroupName" = "custom";"DefaultValue" = "False"; "Description" = "Installs QEMU guest agent services from the Fedora VirtIO website. Defaults to 'False' (no installation will be performed). diff --git a/WinImageBuilder.psm1 b/WinImageBuilder.psm1 index 645cfec..bd54781 100755 --- a/WinImageBuilder.psm1 +++ b/WinImageBuilder.psm1 @@ -57,6 +57,29 @@ $VirtIODriverMappings = @{ "2k25" = @(26100, $MAX_BUILD_NUMBER, $true); } +# Nutanix VirtIO driver folders can be labeled with or without "(Legacy)" depending on version +$nutanixVirtioFolderMappings = @{ + "2k8" = @("Windows Server 2008 (Legacy)", "Windows Server 2008"); + "2k8r2" = @("Windows Server 2008 R2 (Legacy)", "Windows Server 2008 R2"); + "w7" = @("Windows 7 (Legacy)", "Windows 7"); + "2k12" = @("Windows Server 2012 (Legacy)", "Windows Server 2012"); + "w8" = @("Windows 8 (Legacy)", "Windows 8"); + "2k12r2" = @("Windows Server 2012 R2 (Legacy)", "Windows Server 2012 R2"); + "w8.1" = @("Windows 8.1 (Legacy)", "Windows 8.1"); + "2k16" = @("Windows Server 2016"); + "w10" = @("Windows 10"); + "w11" = @("Windows 11"); + "2k19" = @("Windows Server 2019"); + "2k22" = @("Windows Server 2022"); + "2k25" = @("Windows Server 2025"); +} + +$nutanixVirtioArchMappings = @{ + "amd64" = "x64" + "i386" = "x86" + "x86" = "x86" +} + $AvailableCompressionFormats = @("tar","gz","zip") . "$scriptPath\Interop.ps1" @@ -760,6 +783,8 @@ function Get-VirtIODrivers { [parameter(Mandatory=$true)] [bool]$IsServer, [parameter(Mandatory=$true)] + [bool]$IsNutanixTarget, + [parameter(Mandatory=$true)] [string]$BasePath, [parameter(Mandatory=$true)] [string]$Architecture, @@ -768,31 +793,47 @@ function Get-VirtIODrivers { ) Write-Log "Getting Virtual IO Drivers: $BasePath..." - $driverPaths = @() - foreach ($driver in $VirtioDrivers) { - foreach ($osVersion in $VirtIODriverMappings.Keys) { - $map = $VirtIODriverMappings[$osVersion] + $osVersion = $null + foreach ($entry in $VirtIODriverMappings.Keys) { + $map = $VirtIODriverMappings[$entry] $minBuildNumber = $map[0] $maxBuildNumber = $map[1] $isServerVersion = $map[2] - if (!(($BuildNumber -ge $minBuildNumber -and $BuildNumber -le $maxBuildNumber) ` - -and ($isServerVersion -eq $isServer))) { - continue - } - $driverPath = "{0}\{1}\{2}\{3}" -f @($basePath, - $driver, - $osVersion, - $architecture) - if (Test-Path $driverPath) { - $driverPaths += $driverPath + if (($BuildNumber -ge $minBuildNumber -and $BuildNumber -le $maxBuildNumber) ` + -and ($isServerVersion -eq $isServer)) { + $osVersion = $entry break } + } + + $driverPaths = @() + if ($osVersion) { + if (!$IsNutanixTarget){ + foreach ($driver in $VirtioDrivers) { + $driverPath = "{0}\{1}\{2}\{3}" -f @($basePath, + $driver, + $osVersion, + $architecture) + if (Test-Path $driverPath) { + $driverPaths += $driverPath + } + } + } else { + foreach ($folder in $nutanixVirtioFolderMappings[$osVersion]) { + $driverPath = "{0}\{1}\{2}" -f @($basePath, + $folder, + $nutanixVirtioArchMappings[$Architecture]) + if (Test-Path $driverPath) { + $driverPaths += $driverPath + break + } + } } } if (!$driverPaths -and $RecursionDepth -lt 1) { # Note(avladu): Fallback to 2012r2/w8.1 if no drivers are found $driverPaths = Get-VirtIODrivers -BuildNumber 9600 -IsServer $IsServer ` - -BasePath $BasePath -Architecture $Architecture -RecursionDepth 1 + -IsNutanixTarget $IsNutanixTarget -BasePath $BasePath -Architecture $Architecture -RecursionDepth 1 } Write-Log "Finished to get IO Drivers." return $driverPaths @@ -805,6 +846,8 @@ function Add-VirtIODrivers { [parameter(Mandatory=$true)] [object]$image, [parameter(Mandatory=$true)] + [bool]$isNutanixTarget, + [parameter(Mandatory=$true)] [string]$driversBasePath ) @@ -832,8 +875,8 @@ function Add-VirtIODrivers { # For VirtIO ISO with drivers version higher than 1.8.x $buildNumber = [int]$image.ImageVersion.Build $virtioDriversPaths = Get-VirtIODrivers -BuildNumber $buildNumber ` - -IsServer ([bool](Is-ServerInstallationType $image)) -BasePath $driversBasePath ` - -Architecture $image.ImageArchitecture + -IsServer ([bool](Is-ServerInstallationType $image)) -IsNutanixTarget $isNutanixTarget ` + -BasePath $driversBasePath -Architecture $image.ImageArchitecture foreach ($virtioDriversPath in $virtioDriversPaths) { if (Test-Path $virtioDriversPath) { Add-DriversToImage $vhdDriveLetter $virtioDriversPath @@ -857,6 +900,9 @@ function Add-VirtIODriversFromISO { .PARAMETER Image The exact flavor of Windows installed on that image, so that the supported VirtIO drivers can be installed. + .PARAMETER IsNutanixTarget + Indicates whether the image is being built for Nutanix. When true, Nutanix VirtIO ISO + folder mappings are used. .PARAMETER ISOPath The full path of the VirtIO ISO file containing the drivers. #> @@ -866,6 +912,8 @@ function Add-VirtIODriversFromISO { [parameter(Mandatory=$true)] [object]$image, [parameter(Mandatory=$true)] + [bool]$isNutanixTarget, + [parameter(Mandatory=$true)] [string]$isoPath ) Write-Log "Adding Virtual IO Drivers from ISO: $isoPath..." @@ -893,7 +941,7 @@ function Add-VirtIODriversFromISO { $driversBasePath += ":" Write-Log "Adding drivers from $driversBasePath" Add-VirtIODrivers -vhdDriveLetter $vhdDriveLetter -image $image ` - -driversBasePath $driversBasePath + -isNutanixTarget $isNutanixTarget -driversBasePath $driversBasePath } else { throw "The $isoPath is not a valid iso path." } @@ -1587,7 +1635,7 @@ function New-WindowsOnlineImage { Remove-Item -Force $virtualDiskPath } - if ($windowsImageConfig.image_type -eq "KVM") { + if ($windowsImageConfig.image_type -in @("KVM", "Nutanix")) { $imagePath = $barePath + ".qcow2" Write-Log "Converting VHD to Qcow2" Convert-VirtualDisk -vhdPath $virtualDiskPath -outPath $imagePath -format "qcow2" ` @@ -1730,11 +1778,11 @@ function New-WindowsCloudImage { } if ($windowsImageConfig.virtio_iso_path) { Add-VirtIODriversFromISO -vhdDriveLetter $winImagePath -image $image ` - -isoPath $windowsImageConfig.virtio_iso_path + -isNutanixTarget $($windowsImageConfig.image_type -eq "Nutanix") -isoPath $windowsImageConfig.virtio_iso_path } if ($windowsImageConfig.virtio_base_path) { Add-VirtIODrivers -vhdDriveLetter $winImagePath -image $image ` - -driversBasePath $windowsImageConfig.virtio_base_path + -isNutanixTarget $($windowsImageConfig.image_type -eq "Nutanix") -driversBasePath $windowsImageConfig.virtio_base_path } if ($windowsImageConfig.extra_features) { Enable-FeaturesInImage $winImagePath $windowsImageConfig.extra_features.split(",") @@ -1867,7 +1915,7 @@ function New-WindowsFromGoldenImage { $imageInfo = Get-ImageInformation $driveLetterGold -ImageName $windowsImageConfig.image_name if ($windowsImageConfig.virtio_iso_path) { Add-VirtIODriversFromISO -vhdDriveLetter $driveLetterGold -image $imageInfo ` - -isoPath $windowsImageConfig.virtio_iso_path + -isNutanixTarget $($windowsImageConfig.image_type -eq "Nutanix") -isoPath $windowsImageConfig.virtio_iso_path } if ($windowsImageConfig.drivers_path -and (Test-Path $windowsImageConfig.drivers_path)) { @@ -1940,7 +1988,7 @@ function New-WindowsFromGoldenImage { $imagePath = $imagePathRaw } - if ($windowsImageConfig.image_type -eq "KVM") { + if ($windowsImageConfig.image_type -in @("KVM", "Nutanix")) { $imagePathQcow2 = $barePath + ".qcow2" Write-Log "Converting VHD to QCow2" Convert-VirtualDisk -vhdPath $imagePath -outPath $imagePathQcow2 ` @@ -2047,7 +2095,7 @@ function Test-OfflineWindowsImage { $diskFormat = 'vpc' } } - if ($windowsImageConfig.image_type -eq "KVM") { + if ($windowsImageConfig.image_type -in @("KVM", "Nutanix")) { $fileExtension = 'qcow2' $diskFormat = 'qcow2' }