Skip to content

Commit

Permalink
Add Hyper-V option in windows installer
Browse files Browse the repository at this point in the history
podman.msi GUI has a radio-button to select WSL or Hyper-V

The checkbox in podman.msi GUI allow the user to specify if
the machine provider installation (WSL or Hyper-V) should
be part of podman installation or not.

podman-setup.exe supports 2 new variables: MachineProvider
(valid values are `wsl` and `hyperv`) and HyperVCheckbox
(valid values are `0` and `1`)

Installation creates the configuration file
`99-podman-machine-provider.conf` under folder
`%APPDATA\containers\containers.conf.d` with the selected
machine provider

Cirrus CI `win_installer_task` tests the installation with
both `hyperv` and `wsl` and verifies the configuration.
Uninstallation is tested too.

Note that podman-setup.exe GUI doesn't allow to choose the
provider yet. See #22492

Signed-off-by: Mario Loriedo <mario.loriedo@gmail.com>
  • Loading branch information
l0rd authored and openshift-cherrypick-robot committed May 29, 2024
1 parent 4d0cd1b commit 7df3715
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,11 @@ swagger_task:

win_installer_task:
name: "Verify Win Installer Build"
matrix:
- env:
CONTAINERS_MACHINE_PROVIDER: 'wsl'
- env:
CONTAINERS_MACHINE_PROVIDER: 'hyperv'
alias: win_installer
only_if: # RHEL never releases podman windows installer binary
$CIRRUS_TAG == '' &&
Expand Down
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,13 @@ result
# Necessary to prevent hack/tree-status.sh false-positive
/*runner_stats.log
.generate-bindings
contrib/win-installer/artifacts/
contrib/win-installer/docs/
contrib/win-installer/fetch/
contrib/win-installer/podman.msi
contrib/win-installer/podman-*setup.exe
contrib/win-installer/engine.exe
contrib/win-installer/shasums
contrib/win-installer/pages.wxs
contrib/win-installer/*.wixobj
contrib/win-installer/*.wixpdb
51 changes: 44 additions & 7 deletions contrib/cirrus/win-installer-main.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,59 @@

. $PSScriptRoot\win-lib.ps1

Set-Location "$ENV:CIRRUS_WORKING_DIR\repo\contrib\win-installer"
if ($Env:CI -eq "true") {
$WIN_INST_FOLDER = "$ENV:CIRRUS_WORKING_DIR\repo\contrib\win-installer"
$RELEASE_DIR = "$ENV:CIRRUS_WORKING_DIR\repo"
} else {
$WIN_INST_FOLDER = "$PSScriptRoot\..\win-installer"
$ENV:WIN_INST_VER = "9.9.9"
$RELEASE_DIR = "$PSScriptRoot\..\.."
$ENV:CONTAINERS_MACHINE_PROVIDER = "wsl"
}

$ConfFilePath = "$env:ProgramData\containers\containers.conf.d\99-podman-machine-provider.conf"
$WindowsPathsToTest = @("C:\Program Files\RedHat\Podman\podman.exe",
"C:\Program Files\RedHat\Podman\win-sshproxy.exe",
"$ConfFilePath",
"HKLM:\SOFTWARE\Red Hat\Podman")

Set-Location $WIN_INST_FOLDER

# Build Installer
# Note: consumes podman-remote-release-windows_amd64.zip from repo.tbz2
Run-Command ".\build.ps1 $Env:WIN_INST_VER dev `"$ENV:CIRRUS_WORKING_DIR\repo`""
Run-Command ".\build.ps1 $Env:WIN_INST_VER dev `"$RELEASE_DIR`""

# Run the installer silently and WSL install option disabled (prevent reboots, wsl requirements)
# Run the installer silently and WSL/HyperV install options disabled (prevent reboots)
# We need AllowOldWin=1 for server 2019 (cirrus image), can be dropped after server 2022
$ret = Start-Process -Wait -PassThru ".\podman-${ENV:WIN_INST_VER}-dev-setup.exe" -ArgumentList "/install /quiet WSLCheckbox=0 AllowOldWin=1 /log inst.log"
$ret = Start-Process -Wait -PassThru ".\podman-${ENV:WIN_INST_VER}-dev-setup.exe" -ArgumentList "/install /quiet MachineProvider=$ENV:CONTAINERS_MACHINE_PROVIDER WSLCheckbox=0 HyperVCheckbox=0 AllowOldWin=1 /log inst.log"
if ($ret.ExitCode -ne 0) {
Write-Host "Install failed, dumping log"
Get-Content inst.log
throw "Exit code is $($ret.ExitCode)"
}
if (! ((Test-Path -Path "C:\Program Files\RedHat\Podman\podman.exe") -and `
(Test-Path -Path "C:\Program Files\RedHat\Podman\win-sshproxy.exe"))) {
throw "Expected podman.exe and win-sshproxy.exe, one or both not present after install"
$WindowsPathsToTest | ForEach-Object {
if (! (Test-Path -Path $_) ) {
throw "Expected $_ but it's not present after uninstall"
}
}
$machineProvider = Get-Content $ConfFilePath | Select-Object -Skip 1 | ConvertFrom-StringData | ForEach-Object { $_.provider }
if ( $machineProvider -ne "`"$ENV:CONTAINERS_MACHINE_PROVIDER`"" ) {
throw "Expected `"$ENV:CONTAINERS_MACHINE_PROVIDER`" as default machine provider but got $machineProvider"
}

Write-Host "Installer verification successful!"

# Run the uninstaller silently to verify that it cleans up properly
$ret = Start-Process -Wait -PassThru ".\podman-${ENV:WIN_INST_VER}-dev-setup.exe" -ArgumentList "/uninstall /quiet /log uninst.log"
if ($ret.ExitCode -ne 0) {
Write-Host "Uninstall failed, dumping log"
Get-Content uninst.log
throw "Exit code is $($ret.ExitCode)"
}
$WindowsPathsToTest | ForEach-Object {
if ( Test-Path -Path $_ ) {
throw "Path $_ is still present after uninstall"
}
}

Write-Host "Uninstaller verification successful!"
8 changes: 7 additions & 1 deletion contrib/win-installer/burn.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
</BootstrapperApplicationRef>
<Variable Name='InstallFolder' Type='string' Value='[ProgramFiles64Folder]RedHat\Podman' bal:Overridable="yes"/>
<Variable Name="VERSION" Value="$(var.VERSION)"/>
<Variable Name="MachineProvider" Type="string" Value="wsl" bal:Overridable="yes"/>
<Variable Name="WSLCheckbox" Type="numeric" Value="1" bal:Overridable="yes"/>
<Variable Name="HyperVCheckbox" Type="numeric" Value="0" bal:Overridable="yes"/>
<Variable Name="AllowOldWin" Type="numeric" Value="0" bal:Overridable="yes"/>
<Variable Name="LaunchTarget" Value="explorer.exe"/>
<Variable Name="LaunchArguments" Value="&quot;[InstallFolder]\podman-for-windows.html&quot;"/>
<Variable Name="SkipConfigFileCreation" Value="0"/>

<util:RegistrySearch Id="PreviousVersionSearch" Variable="PreviousVersion" Result="value" Root="HKLM" Key="SOFTWARE\[WixBundleManufacturer]\Updates\[WixBundleName]" Value="PackageVersion"/>
<util:RegistrySearch Id="PreviousInstallFolderSearch" Root="HKLM" Key="SOFTWARE\[WixBundleManufacturer]\[WixBundleName]" Value="InstallDir" Variable="PreviousInstallFolder" Win64="yes"/>
Expand All @@ -35,9 +38,12 @@
<Chain>
<MsiPackage Id="Setup" SourceFile="podman.msi" Vital="yes">
<MsiProperty Name="INSTALLDIR" Value="[InstallFolder]" />
<MsiProperty Name="MACHINE_PROVIDER" Value="[MachineProvider]"/>
<MsiProperty Name="WITH_WSL" Value="[WSLCheckbox]"/>
<MsiProperty Name="WITH_HYPERV" Value="[HyperVCheckbox]"/>
<MsiProperty Name="SKIP_CONFIG_FILE_CREATION" Value="[SkipConfigFileCreation]"/>
</MsiPackage>
<ExePackage DisplayName="WSL Kernel Install" InstallCondition="WSLCheckbox = 1" SourceFile="artifacts\podman-wslkerninst.exe"/>
<ExePackage DisplayName="WSL Kernel Install" InstallCondition='(MachineProvider = "wsl") AND (WSLCheckbox = 1)' SourceFile="artifacts\podman-wslkerninst.exe"/>
</Chain>
<OptionalUpdateRegistration/>
</Bundle>
Expand Down
66 changes: 65 additions & 1 deletion contrib/win-installer/podman-msihooks/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
#include <MsiQuery.h>

BOOL isWSLEnabled();
BOOL isHyperVEnabled();
LPCWSTR boolToNStr(BOOL bool);
LPCSTR szSvcNameHyperv = TEXT("vmms");

/**
* CheckWSL is a custom action loaded by the Podman Windows installer
Expand All @@ -28,6 +30,19 @@ LPCWSTR boolToNStr(BOOL bool);
return 0;
}

/**
* CheckHyperV is a custom action loaded by the Podman Windows installer
* to determine whether the system already has Hyper-V installed.
*/

__declspec(dllexport) UINT __cdecl CheckHyperV(MSIHANDLE hInstall) {
BOOL hasHyperV = isHyperVEnabled();
// Set a property with the HyperV state for the installer to operate on
MsiSetPropertyW(hInstall, L"HAS_HYPERVFEATURE", boolToNStr(hasHyperV));

return 0;
}

LPCWSTR boolToNStr(BOOL bool) {
return bool ? L"1" : L"0";
}
Expand All @@ -51,7 +66,7 @@ BOOL isWSLEnabled() {
// CreateProcessW requires lpCommandLine to be mutable
wchar_t cmd[] = L"wsl --set-default-version 2";
if (! CreateProcessW(NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
NULL, NULL, &startup, &process)) {
NULL, NULL, &startup, &process)) {

return FALSE;
}
Expand All @@ -64,3 +79,52 @@ BOOL isWSLEnabled() {

return exitCode == 0;
}

BOOL isHyperVEnabled() {
/*
* Checks if the Windows service `vmms` is running to
* determine if Hyper-V is enabled.
*/
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwBytesNeeded;

// Get a handle to the SCM database.
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // servicesActive database
SERVICE_QUERY_STATUS); // service query access rights

if (NULL == schSCManager) {
return FALSE;
}

// Get a handle to the service.
schService = OpenService(
schSCManager,
szSvcNameHyperv,
SERVICE_QUERY_STATUS);

if (schService == NULL) {
CloseServiceHandle(schSCManager);
return FALSE;
}

// Check the status
if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded ) ) {
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return FALSE;
}

CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);

return ssStatus.dwCurrentState == SERVICE_RUNNING;
}
121 changes: 114 additions & 7 deletions contrib/win-installer/podman.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,83 @@
<Media Id="1" Cabinet="Podman.cab" EmbedCab="yes"/>
<MajorUpgrade AllowDowngrades="yes"/>
<Property Id="DiskPrompt" Value="Red Hat's Podman $(var.VERSION) Installation"/>
<SetProperty Id="WSL_INSTALL" Before="AppSearch" Value="1" Sequence="first">NOT (WITH_WSL = 0)</SetProperty>
<Property Id="MACHINE_PROVIDER" Value="wsl"/>
<Property Id="MACHINE_PROVIDER_CONFIG_FILE_PATH">
<DirectorySearch Id="CommonAppDataFolderSearch" Path="[CommonAppDataFolder]">
<DirectorySearch Id="ContainersFolderSearch" Path="containers">
<DirectorySearch Id="ContainersConfDFolderSearch" Path="containers.conf.d">
<FileSearch Name="99-podman-machine-provider.conf"/>
</DirectorySearch>
</DirectorySearch>
</DirectorySearch>
</Property>
<Property Id="MAIN_EXECUTABLE_FILE_PATH">
<DirectorySearch Id="ProgramFiles64FolderSearch" Path="[ProgramFiles64Folder]">
<DirectorySearch Id="RedHatFolderSearch" Path="RedHat">
<DirectorySearch Id="PodmanFolderSearch" Path="Podman">
<FileSearch Name="podman.exe"/>
</DirectorySearch>
</DirectorySearch>
</DirectorySearch>
</Property>
<!--
Property WSL_INSTALL is set at runtime and used as the condition to run the `WSLFeatureComponent` Component:
WSL is installed only if all these conditions are met:
- WSL isn't already installed
- The user has set property `MACHINE_PROVIDER` to "wsl"
- The user hasn't set property `WITH_WSL` to 0
-->
<SetProperty Id="WSL_INSTALL" Before="AppSearch" Value="1" Sequence="first">
<![CDATA[
(HAS_WSLFEATURE = 0)
AND (MACHINE_PROVIDER = "wsl")
AND (NOT (WITH_WSL = 0))
]]>
</SetProperty>
<!--
Property HYPERV_INSTALL is set at runtime and used as the condition to run the `HyperVFeatureComponent` Component:
HyperV is installed only if all these conditions are met:
- HyperV isn't already installed
- The user has set property `MACHINE_PROVIDER` to "hyperv"
- The user hasn't set property `WITH_HYPERV` to 0
-->
<SetProperty Id="HYPERV_INSTALL" Before="AppSearch" Value="1" Sequence="first">
<![CDATA[
(HAS_HYPERVFEATURE = 0)
AND (MACHINE_PROVIDER = "hyperv")
AND (NOT (WITH_HYPERV = 0))
]]>
</SetProperty>
<!--
Property CREATE_MACHINE_PROVIDER_CONFIG_FILE is set at runtime and used as the condition to run the `MachineProviderConfigFile` Component:
The machine provider config file is created only if all these conditions are met:
- The user hasn't set property `SKIP_CONFIG_FILE_CREATION` to 1
- The machine provider config file ($PROGRAMDATA/containers/containers.conf.d/99-podman-machine-provider.conf) doesn't exist
- The main executable file ($PROGRAMDATA/RedHat/Podman/podman.exe) doesn't exist
-->
<SetProperty Id="CREATE_MACHINE_PROVIDER_CONFIG_FILE" After="AppSearch" Value="1" Sequence="first">
<![CDATA[
(NOT (SKIP_CONFIG_FILE_CREATION = 1))
AND (NOT MACHINE_PROVIDER_CONFIG_FILE_PATH)
AND (NOT MAIN_EXECUTABLE_FILE_PATH)
]]>
</SetProperty>
<!--
Property HIDE_PROVIDER_CHOICE is set at runtime and used as the condition to hide the Machine Provider
choice from the MSI GUI (the Radio Button Group and other related controls):
The machine provider choice isn't shown to the user if one of these conditions are met:
- The user has set the property `SKIP_CONFIG_FILE_CREATION` to 1
- The machine provider config file ($PROGRAMDATA/containers/containers.conf.d/99-podman-machine-provider.conf) exists
- The main executable file ($PROGRAMDATA/RedHat/Podman/podman.exe) exists
-->
<SetProperty Id="HIDE_PROVIDER_CHOICE" After="AppSearch" Value="1" Sequence="first">
<![CDATA[
(SKIP_CONFIG_FILE_CREATION = 1)
OR (MACHINE_PROVIDER_CONFIG_FILE_PATH)
OR (MAIN_EXECUTABLE_FILE_PATH)
]]>
</SetProperty>

<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder" Name="PFiles">
<Directory Id="RedHatPFiles" Name="RedHat">
Expand Down Expand Up @@ -48,6 +124,22 @@
</Directory>
</Directory>
</Directory>
<!--
The following code creates the `containers/containers.conf.d` folder under the system wide
`$CommonAppDataFolder`. That's preferred to the user specific `$AppDataFolder` to avoid the
Windows Installer ICE91 warning https://learn.microsoft.com/en-us/windows/win32/msi/ice91.
-->
<Directory Id="CommonAppDataFolder">
<Directory Id="CONFIGDIR" Name="containers">
<Directory Id="ContainersConfigSubDir" Name="containers.conf.d">
<Component Id="MachineProviderConfigFile" Guid="C32C0040-D9AF-4155-AC7E-465B63B6BE3B">
<CreateFolder />
<IniFile Id="MachineProviderConfigFile" Action="createLine" Directory="ContainersConfigSubDir" Section="machine" Name="99-podman-machine-provider.conf" Key="provider" Value='"[MACHINE_PROVIDER]"' />
<Condition>CREATE_MACHINE_PROVIDER_CONFIG_FILE</Condition>
</Component>
</Directory>
</Directory>
</Directory>
<Directory Id="EnvEntries">
<Component Id="EnvEntriesComponent" Guid="b662ec43-0e0e-4018-8bf3-061904bb8f5b" Win64="yes">
<CreateFolder />
Expand All @@ -57,16 +149,24 @@
</Directory>

<CustomAction Id="OpenGuide" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<CustomAction Id="CheckWSL" BinaryKey="PodmanHooks" Execute="immediate" DllEntry="CheckWSL" />
<CustomAction Id="CheckWSL" BinaryKey="PodmanHooks" Execute="firstSequence" DllEntry="CheckWSL" />
<CustomAction Id="CheckHyperV" BinaryKey="PodmanHooks" Execute="firstSequence" DllEntry="CheckHyperV" />
<CustomActionRef Id="WixBroadcastEnvironmentChange" />
<ComponentGroup Id="WSLFeature" Directory="INSTALLDIR">
<Component>
<Condition>(NOT Installed) AND WSL_INSTALL = 1 AND HAS_WSLFEATURE = 0</Condition>
<File Source="$(sys.SOURCEFILEPATH)"/>
<Component Id="WSLFeatureComponent" Guid="F6A693BC-186C-4E64-8015-C3073013B3A8">
<Condition>(NOT Installed) AND WSL_INSTALL = 1</Condition>
<CreateFolder />
<PanelSW:Dism EnableFeature="VirtualMachinePlatform" ErrorHandling="prompt"/>
<PanelSW:Dism EnableFeature="Microsoft-Windows-Subsystem-Linux" ErrorHandling="prompt"/>
</Component>
</ComponentGroup>
<ComponentGroup Id="HyperVFeature" Directory="INSTALLDIR">
<Component Id="HyperVFeatureComponent" Guid="F7B2D4C9-6C89-46BB-B4EA-FF39424972F3">
<Condition>(NOT Installed) AND HYPERV_INSTALL = 1</Condition>
<CreateFolder />
<PanelSW:Dism EnableFeature="Microsoft-Hyper-V" ErrorHandling="prompt"/>
</Component>
</ComponentGroup>
<Feature Id="Complete" Level="1">
<ComponentRef Id="INSTALLDIR_Component"/>
<ComponentRef Id="EnvEntriesComponent"/>
Expand All @@ -76,8 +176,10 @@
<ComponentRef Id="GvProxyExecutable"/>
<?endif?>
<ComponentRef Id="GuideHTMLComponent"/>
<ComponentRef Id="MachineProviderConfigFile"/>
<ComponentGroupRef Id="ManFiles"/>
<ComponentGroupRef Id="WSLFeature"/>
<ComponentGroupRef Id="HyperVFeature"/>
</Feature>

<Icon Id="podman.ico" SourceFile="resources/podman-logo.ico"/>
Expand All @@ -94,8 +196,13 @@
</UI>

<InstallExecuteSequence>
<Custom Action="CheckWSL" After="SetWSL_INSTALL">WSL_INSTALL = 1</Custom>
<ForceReboot Before="StopServices">(NOT Installed) AND WSL_INSTALL = 1 AND HAS_WSLFEATURE = 0 AND NOT AFTERREBOOT</ForceReboot>
<Custom Action="CheckWSL" Before="SetWSL_INSTALL" />
<Custom Action="CheckHyperV" Before="SetHYPERV_INSTALL" />
<ForceReboot Before="StopServices">
(NOT Installed)
AND ((WSL_INSTALL = 1) OR (HYPERV_INSTALL = 1))
AND (NOT AFTERREBOOT)
</ForceReboot>
</InstallExecuteSequence>
<Binary Id="PodmanHooks" SourceFile="artifacts/podman-msihooks.dll" />
</Product>
Expand Down
Binary file modified contrib/win-installer/resources/podman-dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 7df3715

Please sign in to comment.