]> git.apps.os.sepia.ceph.com Git - ceph-build.git/commitdiff
[ceph-windows-image-build] Fix Windows image build
authorIonut Balutoiu <ibalutoiu@cloudbasesolutions.com>
Fri, 29 Apr 2022 10:08:43 +0000 (13:08 +0300)
committerIonut Balutoiu <ibalutoiu@cloudbasesolutions.com>
Fri, 29 Apr 2022 16:17:29 +0000 (19:17 +0300)
The `${VIRTIO_WIN_PATH}\guest-agent\qemu-ga-x86_64.msi` unattended
installation fails with latest virtio.

Refactor the setup scripts to only install the required drivers (`NetKVM`,
`viostor`, `vioserial`), and use a single script (`first-logon.ps1`) for
provisioning the Windows OS.

Also, add a separate script `utils.ps1` with common PowerShell functions.

ceph-windows-image-build/build/autounattend.xml
ceph-windows-image-build/build/build
ceph-windows-image-build/build/first-logon.ps1 [new file with mode: 0644]
ceph-windows-image-build/build/install-openssh-server.ps1 [deleted file]
ceph-windows-image-build/build/install-virtio-guest-tools.ps1 [deleted file]
ceph-windows-image-build/build/setup.ps1
ceph-windows-image-build/build/utils.ps1 [new file with mode: 0644]

index 31cedeb759fdccc88efab967b82168d45acab0bf..93b075256fbb1ca91e6871c00db79cb9a4c0c5c4 100644 (file)
         <PathAndCredentials wcm:action="add" wcm:keyValue="1">
           <Path>E:\NetKVM\2k19\amd64\</Path>
         </PathAndCredentials>
-        <PathAndCredentials wcm:action="add" wcm:keyValue="3">
+        <PathAndCredentials wcm:action="add" wcm:keyValue="2">
           <Path>E:\viostor\2k19\amd64\</Path>
         </PathAndCredentials>
+        <PathAndCredentials wcm:action="add" wcm:keyValue="3">
+          <Path>E:\vioserial\2k19\amd64\</Path>
+        </PathAndCredentials>
       </DriverPaths>
     </component>
 
       <FirstLogonCommands>
 
         <SynchronousCommand wcm:action="add">
-          <CommandLine>%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell -NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -File A:\install-virtio-guest-tools.ps1</CommandLine>
+          <CommandLine>%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -File A:\first-logon.ps1</CommandLine>
           <Order>1</Order>
         </SynchronousCommand>
 
-        <SynchronousCommand wcm:action="add">
-          <CommandLine>%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell -NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -File A:\install-openssh-server.ps1</CommandLine>
-          <Order>2</Order>
-        </SynchronousCommand>
-
       </FirstLogonCommands>
 
     </component>
index d33e7bdcbdba91929bdd06fd929c6d995b4f9d12..6f17c51023612fa308ff0cfe0ec0a713e5688087 100755 (executable)
@@ -74,8 +74,8 @@ sudo mount ${BUILD_DIR}/floppy.img ${BUILD_DIR}/floppy
 ssh-keygen -y -f $SSH_PRIVATE_KEY > ${BUILD_DIR}/id_rsa.pub
 sudo cp \
     ${BUILD_DIR}/autounattend.xml \
-    ${BUILD_DIR}/install-virtio-guest-tools.ps1 \
-    ${BUILD_DIR}/install-openssh-server.ps1 \
+    ${BUILD_DIR}/first-logon.ps1 \
+    ${BUILD_DIR}/utils.ps1 \
     ${BUILD_DIR}/id_rsa.pub \
     ${BUILD_DIR}/floppy/
 sudo umount ${BUILD_DIR}/floppy
@@ -139,9 +139,10 @@ ssh_exec powershell.exe Remove-Item -Force /install-windows-updates.ps1
 
 restart_windows_vm 1800
 
+scp_upload ${BUILD_DIR}/utils.ps1 /utils.ps1
 scp_upload ${BUILD_DIR}/setup.ps1 /setup.ps1
 SSH_TIMEOUT=1h ssh_exec powershell.exe -File /setup.ps1
-ssh_exec powershell.exe Remove-Item -Force /setup.ps1
+ssh_exec powershell.exe Remove-Item -Force /setup.ps1, /utils.ps1
 
 restart_windows_vm
 
diff --git a/ceph-windows-image-build/build/first-logon.ps1 b/ceph-windows-image-build/build/first-logon.ps1
new file mode 100644 (file)
index 0000000..7360d71
--- /dev/null
@@ -0,0 +1,38 @@
+$ErrorActionPreference = "Stop"
+
+. "${PSScriptRoot}\utils.ps1"
+
+$VIRTIO_WIN_PATH = "E:\"
+
+# Install QEMU quest agent
+Write-Output "Installing QEMU guest agent"
+$p = Start-Process -FilePath "msiexec.exe" -ArgumentList @("/i", "${VIRTIO_WIN_PATH}\guest-agent\qemu-ga-x86_64.msi", "/qn") -NoNewWindow -PassThru -Wait
+if($p.ExitCode) {
+    Throw "The QEMU guest agent installation failed. Exit code: $($p.ExitCode)"
+}
+Write-Output "Successfully installed QEMU guest agent"
+
+# Install OpenSSH server
+Start-ExecuteWithRetry {
+    Get-WindowsCapability -Online -Name OpenSSH* | Add-WindowsCapability -Online
+}
+Set-Service -Name "sshd" -StartupType Automatic
+Stop-Service -Name "sshd"
+
+# Create SSH firewall rule
+New-NetFirewallRule -Name "sshd" -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
+
+# Authorize the SSH key
+$authorizedKeysFile = Join-Path $env:ProgramData "ssh\administrators_authorized_keys"
+New-Item -ItemType File -Path $authorizedKeysFile -Force
+Set-Content -Path $authorizedKeysFile -Value (Get-Content "${PSScriptRoot}\id_rsa.pub") -Encoding ascii
+$acl = Get-Acl $authorizedKeysFile
+$acl.SetAccessRuleProtection($true, $false)
+$administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule("Administrators", "FullControl", "Allow")
+$systemRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM", "FullControl", "Allow")
+$acl.SetAccessRule($administratorsRule)
+$acl.SetAccessRule($systemRule)
+$acl | Set-Acl
+
+# Reboot the machine to complete first logon process
+Restart-Computer -Force -Confirm:$false
diff --git a/ceph-windows-image-build/build/install-openssh-server.ps1 b/ceph-windows-image-build/build/install-openssh-server.ps1
deleted file mode 100644 (file)
index aa96ea0..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-$ErrorActionPreference = "Stop"
-
-Get-WindowsCapability -Online -Name OpenSSH* | Add-WindowsCapability -Online
-
-Set-Service -Name "sshd" -StartupType Automatic
-Start-Service -Name "sshd"
-
-New-NetFirewallRule -Name "sshd" -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
-
-# Authorize the SSH key
-$authorizedKeysFile = Join-Path $env:ProgramData "ssh\administrators_authorized_keys"
-Set-Content -Path $authorizedKeysFile -Value (Get-Content "${PSScriptRoot}\id_rsa.pub") -Encoding ascii
-$acl = Get-Acl $authorizedKeysFile
-$acl.SetAccessRuleProtection($true, $false)
-$administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule("Administrators", "FullControl", "Allow")
-$systemRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM", "FullControl", "Allow")
-$acl.SetAccessRule($administratorsRule)
-$acl.SetAccessRule($systemRule)
-$acl | Set-Acl
diff --git a/ceph-windows-image-build/build/install-virtio-guest-tools.ps1 b/ceph-windows-image-build/build/install-virtio-guest-tools.ps1
deleted file mode 100644 (file)
index a8d4379..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-$ErrorActionPreference = "Stop"
-
-$VIRTIO_WIN_PATH = "E:\"
-
-Write-Output "Installing virtio-win guest tools"
-
-# Trust driver certs
-$certStore = Get-Item "cert:\LocalMachine\TrustedPublisher"
-$certStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
-$driverPath = Get-Item "${VIRTIO_WIN_PATH}\*\2k19\amd64"
-Get-ChildItem -Recurse -Path $driverPath -Filter "*.cat" | ForEach-Object {
-    $cert = (Get-AuthenticodeSignature $_.FullName).SignerCertificate
-    $certStore.Add($cert)
-}
-$certStore.Close()
-
-# Install QEMU quest tools
-$p = Start-Process -FilePath "${VIRTIO_WIN_PATH}\virtio-win-guest-tools.exe" -ArgumentList @("/install", "/quiet", "/norestart") -NoNewWindow -PassThru -Wait
-if($p.ExitCode) {
-    Throw "The virtio-win guest tools installation failed. Exit code: $($p.ExitCode)"
-}
-
-Write-Output "Successfully installed virtio-win guest tools"
index 75414fc2b3a099e669e92bf4afa8b696da71bcdf..08ae67366ea7586298ad82b4d6a874d67af8da21 100644 (file)
@@ -1,6 +1,8 @@
 $ErrorActionPreference = "Stop"
 $ProgressPreference = "SilentlyContinue"
 
+. "${PSScriptRoot}\utils.ps1"
+
 $VS_2019_BUILD_TOOLS_URL = "https://aka.ms/vs/16/release/vs_buildtools.exe"
 $WDK_URL = "https://download.microsoft.com/download/7/d/6/7d602355-8ae9-414c-ae36-109ece2aade6/wdk/wdksetup.exe"  # Windows 11 WDK (22000.1). It can be used to develop drivers for previous OS releases.
 $PYTHON3_URL = "https://www.python.org/ftp/python/3.10.1/python-3.10.1-amd64.exe"
@@ -17,126 +19,6 @@ function Get-WindowsBuildInfo {
     return $table
 }
 
-function Invoke-CommandLine {
-    Param(
-        [Parameter(Mandatory=$true)]
-        [String]$Command,
-        [String]$Arguments,
-        [Int[]]$AllowedExitCodes=@(0)
-    )
-    & $Command $Arguments.Split(" ")
-    if($LASTEXITCODE -notin $AllowedExitCodes) {
-        Throw "$Command $Arguments returned a non zero exit code ${LASTEXITCODE}."
-    }
-}
-
-function Start-ExecuteWithRetry {
-    Param(
-        [Parameter(Mandatory=$true)]
-        [ScriptBlock]$ScriptBlock,
-        [Int]$MaxRetryCount=10,
-        [Int]$RetryInterval=3,
-        [String]$RetryMessage,
-        [Array]$ArgumentList=@()
-    )
-    $currentErrorActionPreference = $ErrorActionPreference
-    $ErrorActionPreference = "Continue"
-    $retryCount = 0
-    while ($true) {
-        try {
-            $res = Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList
-            $ErrorActionPreference = $currentErrorActionPreference
-            return $res
-        } catch [System.Exception] {
-            $retryCount++
-            if ($retryCount -gt $MaxRetryCount) {
-                $ErrorActionPreference = $currentErrorActionPreference
-                Throw $_
-            } else {
-                $prefixMsg = "Retry(${retryCount}/${MaxRetryCount})"
-                if($RetryMessage) {
-                    Write-Host "${prefixMsg} - $RetryMessage"
-                } elseif($_) {
-                    Write-Host "${prefixMsg} - $($_.ToString())"
-                }
-                Start-Sleep $RetryInterval
-            }
-        }
-    }
-}
-
-function Start-FileDownload {
-    Param(
-        [Parameter(Mandatory=$true)]
-        [String]$URL,
-        [Parameter(Mandatory=$true)]
-        [String]$Destination,
-        [Int]$RetryCount=10
-    )
-    Write-Output "Downloading $URL to $Destination"
-    Start-ExecuteWithRetry `
-        -ScriptBlock { Invoke-CommandLine -Command "curl.exe" -Arguments "-L -s -o $Destination $URL" } `
-        -MaxRetryCount $RetryCount `
-        -RetryMessage "Failed to download '${URL}'. Retrying"
-    Write-Output "Successfully downloaded."
-}
-
-function Add-ToPathEnvVar {
-    Param(
-        [Parameter(Mandatory=$true)]
-        [String[]]$Path,
-        [Parameter(Mandatory=$false)]
-        [ValidateSet([System.EnvironmentVariableTarget]::User, [System.EnvironmentVariableTarget]::Machine)]
-        [System.EnvironmentVariableTarget]$Target=[System.EnvironmentVariableTarget]::Machine
-    )
-    $pathEnvVar = [Environment]::GetEnvironmentVariable("PATH", $Target).Split(';')
-    $currentSessionPath = $env:PATH.Split(';')
-    foreach($p in $Path) {
-        if($p -notin $pathEnvVar) {
-            $pathEnvVar += $p
-        }
-        if($p -notin $currentSessionPath) {
-            $currentSessionPath += $p
-        }
-    }
-    $env:PATH = $currentSessionPath -join ';'
-    $newPathEnvVar = $pathEnvVar -join ';'
-    [Environment]::SetEnvironmentVariable("PATH", $newPathEnvVar, $Target)
-}
-
-function Install-Tool {
-    [CmdletBinding(DefaultParameterSetName = "URL")]
-    Param(
-        [Parameter(Mandatory=$true, ParameterSetName = "URL")]
-        [String]$URL,
-        [Parameter(Mandatory=$true, ParameterSetName = "LocalPath")]
-        [String]$LocalPath,
-        [Parameter(ParameterSetName = "URL")]
-        [Parameter(ParameterSetName = "LocalPath")]
-        [String[]]$Params=@(),
-        [Parameter(ParameterSetName = "URL")]
-        [Parameter(ParameterSetName = "LocalPath")]
-        [Int[]]$AllowedExitCodes=@(0)
-    )
-    PROCESS {
-        $installerPath = $LocalPath
-        if($PSCmdlet.ParameterSetName -eq "URL") {
-            $installerPath = Join-Path $env:TEMP $URL.Split('/')[-1]
-            Start-FileDownload -URL $URL -Destination $installerPath
-        }
-        Write-Output "Installing ${installerPath}"
-        $p = Start-Process -FilePath $installerPath -ArgumentList $Params -NoNewWindow -PassThru -Wait
-        if($p.ExitCode -notin $AllowedExitCodes) {
-            Throw "Installation failed. Exit code: $($p.ExitCode)"
-        }
-        if($PSCmdlet.ParameterSetName -eq "URL") {
-            Start-ExecuteWithRetry `
-                -ScriptBlock { Remove-Item -Force -Path $installerPath -ErrorAction Stop } `
-                -RetryMessage "Failed to remove ${installerPath}. Retrying"
-        }
-    }
-}
-
 function Get-GitHubReleaseAssets {
     Param(
         [Parameter(Mandatory=$true)]
diff --git a/ceph-windows-image-build/build/utils.ps1 b/ceph-windows-image-build/build/utils.ps1
new file mode 100644 (file)
index 0000000..f29ab79
--- /dev/null
@@ -0,0 +1,130 @@
+function Invoke-CommandLine {
+    Param(
+        [Parameter(Mandatory=$true)]
+        [String]$Command,
+        [String]$Arguments,
+        [Int[]]$AllowedExitCodes=@(0)
+    )
+    & $Command $Arguments.Split(" ")
+    if($LASTEXITCODE -notin $AllowedExitCodes) {
+        Throw "$Command $Arguments returned a non zero exit code ${LASTEXITCODE}."
+    }
+}
+
+function Start-ExecuteWithRetry {
+    Param(
+        [Parameter(Mandatory=$true)]
+        [ScriptBlock]$ScriptBlock,
+        [Int]$MaxRetryCount=10,
+        [Int]$RetryInterval=3,
+        [String]$RetryMessage,
+        [Array]$ArgumentList=@()
+    )
+    $currentErrorActionPreference = $ErrorActionPreference
+    $ErrorActionPreference = "Continue"
+    $retryCount = 0
+    while ($true) {
+        try {
+            $res = Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList
+            $ErrorActionPreference = $currentErrorActionPreference
+            return $res
+        } catch [System.Exception] {
+            $retryCount++
+            if ($retryCount -gt $MaxRetryCount) {
+                $ErrorActionPreference = $currentErrorActionPreference
+                Throw $_
+            } else {
+                $prefixMsg = "Retry(${retryCount}/${MaxRetryCount})"
+                if($RetryMessage) {
+                    Write-Host "${prefixMsg} - $RetryMessage"
+                } elseif($_) {
+                    Write-Host "${prefixMsg} - $($_.ToString())"
+                }
+                Start-Sleep $RetryInterval
+            }
+        }
+    }
+}
+
+function Start-FileDownload {
+    Param(
+        [Parameter(Mandatory=$true)]
+        [String]$URL,
+        [Parameter(Mandatory=$true)]
+        [String]$Destination,
+        [Int]$RetryCount=10
+    )
+    Write-Output "Downloading $URL to $Destination"
+    Start-ExecuteWithRetry `
+        -ScriptBlock { Invoke-CommandLine -Command "curl.exe" -Arguments "-L -s -o $Destination $URL" } `
+        -MaxRetryCount $RetryCount `
+        -RetryMessage "Failed to download '${URL}'. Retrying"
+    Write-Output "Successfully downloaded."
+}
+
+function Add-ToPathEnvVar {
+    Param(
+        [Parameter(Mandatory=$true)]
+        [String[]]$Path,
+        [Parameter(Mandatory=$false)]
+        [ValidateSet([System.EnvironmentVariableTarget]::User, [System.EnvironmentVariableTarget]::Machine)]
+        [System.EnvironmentVariableTarget]$Target=[System.EnvironmentVariableTarget]::Machine
+    )
+    $pathEnvVar = [Environment]::GetEnvironmentVariable("PATH", $Target).Split(';')
+    $currentSessionPath = $env:PATH.Split(';')
+    foreach($p in $Path) {
+        if($p -notin $pathEnvVar) {
+            $pathEnvVar += $p
+        }
+        if($p -notin $currentSessionPath) {
+            $currentSessionPath += $p
+        }
+    }
+    $env:PATH = $currentSessionPath -join ';'
+    $newPathEnvVar = $pathEnvVar -join ';'
+    [Environment]::SetEnvironmentVariable("PATH", $newPathEnvVar, $Target)
+}
+
+function Install-Tool {
+    [CmdletBinding(DefaultParameterSetName = "URL")]
+    Param(
+        [Parameter(Mandatory=$true, ParameterSetName = "URL")]
+        [String]$URL,
+        [Parameter(Mandatory=$true, ParameterSetName = "LocalPath")]
+        [String]$LocalPath,
+        [Parameter(ParameterSetName = "URL")]
+        [Parameter(ParameterSetName = "LocalPath")]
+        [String[]]$Params=@(),
+        [Parameter(ParameterSetName = "URL")]
+        [Parameter(ParameterSetName = "LocalPath")]
+        [Int[]]$AllowedExitCodes=@(0)
+    )
+    PROCESS {
+        $installerPath = $LocalPath
+        if($PSCmdlet.ParameterSetName -eq "URL") {
+            $installerPath = Join-Path $env:TEMP $URL.Split('/')[-1]
+            Start-FileDownload -URL $URL -Destination $installerPath
+        }
+        Write-Output "Installing ${installerPath}"
+        $kwargs = @{
+            "FilePath" = $installerPath
+            "ArgumentList" = $Params
+            "NoNewWindow" = $true
+            "PassThru" = $true
+            "Wait" = $true
+        }
+        if((Get-ChildItem $installerPath).Extension -eq '.msi') {
+            $kwargs["FilePath"] = "msiexec.exe"
+            $kwargs["ArgumentList"] = @("/i", $installerPath) + $Params
+        }
+        $p = Start-Process @kwargs
+        if($p.ExitCode -notin $AllowedExitCodes) {
+            Throw "Installation failed. Exit code: $($p.ExitCode)"
+        }
+        if($PSCmdlet.ParameterSetName -eq "URL") {
+            Start-ExecuteWithRetry `
+                -ScriptBlock { Remove-Item -Force -Path $installerPath -ErrorAction Stop } `
+                -RetryMessage "Failed to remove ${installerPath}. Retrying"
+        }
+    }
+}