From a776b3afe503cf4c225e46d487f2c561f63ea5c7 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Fri, 4 Oct 2024 08:33:35 +0200 Subject: [PATCH] Fix for missing linux executables and hanging PSSessions (#3698) Fix issue where linux executables are missing in the AL Language Extension (use dotnet to execute the commands instead) Fix issue where PowerShell sometimes hangs when trying to establish a new PSSession shortly after removing another PSSession (Noticed during end 2 end tests on AL-Go for GitHub) --------- Co-authored-by: freddydk --- AppHandling/Run-TestsInNavContainer.ps1 | 5 +- .../Compile-AppWithBcCompilerFolder.ps1 | 6 ++ ContainerHandling/Get-NavContainerSession.ps1 | 40 +++++------ .../Remove-NavContainerSession.ps1 | 38 +++++----- HelperFunctions.ps1 | 69 +++++++++++++++---- ReleaseNotes.txt | 2 + 6 files changed, 99 insertions(+), 61 deletions(-) diff --git a/AppHandling/Run-TestsInNavContainer.ps1 b/AppHandling/Run-TestsInNavContainer.ps1 index f46dfc783..b56a28093 100644 --- a/AppHandling/Run-TestsInNavContainer.ps1 +++ b/AppHandling/Run-TestsInNavContainer.ps1 @@ -149,7 +149,6 @@ try { $navversion = Get-BcContainerNavversion -containerOrImageName $containerName $version = [System.Version]($navversion.split('-')[0]) $PsTestToolFolder = Join-Path $bcContainerHelperConfig.hostHelperFolder "Extensions\$containerName\PsTestTool" - } elseif ($compilerFolder) { Write-Host "Using CompilerFolder" @@ -318,7 +317,6 @@ try { if ($containerName) { if (!((Test-Path $newtonSoftDllPath) -and (Test-Path $clientDllPath))) { Invoke-ScriptInBcContainer -containerName $containerName { Param([string] $myNewtonSoftDllPath, [string] $myClientDllPath) - if (!(Test-Path $myNewtonSoftDllPath)) { $newtonSoftDllPath = "C:\Program Files\Microsoft Dynamics NAV\*\Service\Management\Newtonsoft.Json.dll" if (!(Test-Path $newtonSoftDllPath)) { @@ -410,7 +408,6 @@ try { } } else { - $containerXUnitResultFileName = "" if ($XUnitResultFileName) { $containerXUnitResultFileName = Get-BcContainerPath -containerName $containerName -path $XUnitResultFileName @@ -475,7 +472,7 @@ try { if ($profile) { $serviceUrl += "&profile=$([Uri]::EscapeDataString($profile))" } - + . $PsTestFunctionsPath -newtonSoftDllPath $newtonSoftDllPath -clientDllPath $clientDllPath -clientContextScriptPath $ClientContextPath Write-Host "Connecting to $serviceUrl" diff --git a/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 b/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 index 109f9b2d8..fc57086d0 100644 --- a/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 +++ b/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 @@ -349,6 +349,12 @@ try { } } + if (!(Test-Path -Path (Join-Path $alcPath $alcExe))) { + $alcCmd = "dotnet" + $alcExe = 'alc.dll' + $alcParameters += @((Join-Path $alcPath $alcExe)) + Write-Host "No alc executable in $compilerPlatform. Using dotnet to run alc.dll." + } $alcItem = Get-Item -Path (Join-Path $alcPath $alcExe) [System.Version]$alcVersion = $alcItem.VersionInfo.FileVersion diff --git a/ContainerHandling/Get-NavContainerSession.ps1 b/ContainerHandling/Get-NavContainerSession.ps1 index 007298656..afb187b0f 100644 --- a/ContainerHandling/Get-NavContainerSession.ps1 +++ b/ContainerHandling/Get-NavContainerSession.ps1 @@ -26,37 +26,29 @@ function Get-BcContainerSession { Process { $newsession = $false $session = $null - if ($sessions.ContainsKey($containerName)) { - $session = $sessions[$containerName] + [System.Version]$platformVersion = Get-BcContainerPlatformVersion -containerOrImageName $containerName + if ($platformVersion.Major -lt 24) { + $usePwsh = $false + } + $configurationName = 'Microsoft.PowerShell' + if ($usePwsh) { + $configurationName = 'PowerShell.7' + } + $cacheName = "$containerName-$configurationName" + if ($sessions.ContainsKey($cacheName)) { + $session = $sessions[$cacheName] try { - $platformVersion = Invoke-Command -Session $session -ScriptBlock { [System.Version](get-item 'C:\Program Files\Microsoft Dynamics NAV\*\Service\Microsoft.Dynamics.Nav.Server.exe').Versioninfo.FileVersion } - if ($platformVersion.Major -ge 24 -and ($usePwsh -xor $session.ConfigurationName -eq 'PowerShell.7')) { - # Cannot use existing session - Remove-PSSession -Session $session - $sessions.Remove($containerName) - $session = $null - } - else { - if (!$reinit) { - return $session - } + Invoke-Command -Session $session -ScriptBlock { $PID } | Out-Null + if (!$reinit) { + return $session } } catch { - Remove-PSSession -Session $session - $sessions.Remove($containerName) + $sessions.Remove($cacheName) $session = $null } } if (!$session) { - [System.Version]$platformVersion = Get-BcContainerPlatformVersion -containerOrImageName $containerName - if ($platformVersion.Major -lt 24) { - $usePwsh = $false - } - $configurationName = 'Microsoft.PowerShell' - if ($usePwsh) { - $configurationName = 'PowerShell.7' - } if ($isInsideContainer) { $session = New-PSSession -Credential $bcContainerHelperConfig.WinRmCredentials -ComputerName $containerName -Authentication Basic -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck) } @@ -118,7 +110,7 @@ function Get-BcContainerSession { Set-Location $runPath } -ArgumentList $silent if ($newsession) { - $sessions.Add($containerName, $session) + $sessions.Add($cacheName, $session) } return $session } diff --git a/ContainerHandling/Remove-NavContainerSession.ps1 b/ContainerHandling/Remove-NavContainerSession.ps1 index c3bec2fd6..ff41b813e 100644 --- a/ContainerHandling/Remove-NavContainerSession.ps1 +++ b/ContainerHandling/Remove-NavContainerSession.ps1 @@ -20,18 +20,24 @@ function Remove-BcContainerSession { ) Process { - if ($sessions.ContainsKey($containerName)) { - $session = $sessions[$containerName] - try { - if ($killPsSessionProcess -and !$isInsideContainer) { - $inspect = docker inspect $containerName | ConvertFrom-Json - if ($inspect.HostConfig.Isolation -eq "process") { - try { - $processID = Invoke-Command -Session $session -ScriptBlock { $PID } - Stop-Process -Id $processID -Force + foreach($configurationName in @('Microsoft.PowerShell','PowerShell.7')) { + $cacheName = "$containerName-$configurationName" + if ($sessions.ContainsKey($cacheName)) { + $session = $sessions[$cacheName] + try { + if ($killPsSessionProcess -and !$isInsideContainer) { + $inspect = docker inspect $containerName | ConvertFrom-Json + if ($inspect.HostConfig.Isolation -eq "process") { + try { + $processID = Invoke-Command -Session $session -ScriptBlock { $PID } + Stop-Process -Id $processID -Force + } + catch { + Write-Host "Error killing process in container" + Remove-PSSession -Session $session + } } - catch { - Write-Host "Error killing process in container" + else { Remove-PSSession -Session $session } } @@ -39,15 +45,11 @@ function Remove-BcContainerSession { Remove-PSSession -Session $session } } - else { - Remove-PSSession -Session $session + catch { + Write-Host "Error removing session for container" } + $sessions.Remove($cacheName) } - catch { - Write-Host "Error removing session for container" - } - - $sessions.Remove($containerName) } } } diff --git a/HelperFunctions.ps1 b/HelperFunctions.ps1 index 55454aaeb..5893ff590 100644 --- a/HelperFunctions.ps1 +++ b/HelperFunctions.ps1 @@ -1053,25 +1053,45 @@ function GetAppInfo { } Write-GroupStart -Message "Getting .app info $cacheAppInfoPath" $binPath = Join-Path $compilerFolder 'compiler/extension/bin' + $alToolDll = '' if ($isLinux) { $alcPath = Join-Path $binPath 'linux' - $alToolExe = Join-Path $alcPath 'altool' - & /usr/bin/env sudo pwsh -command "& chmod +x $alToolExe" + $command = Join-Path $alcPath 'altool' + if (Test-Path $command) { + Write-Host "Setting execute permissions on altool" + & /usr/bin/env sudo pwsh -command "& chmod +x $command" + $alToolExists = $true + } + else { + Write-Host "No altool executable found. Using dotnet to run altool.dll." + $command = 'dotnet' + $alToolDll = Join-Path $alcPath 'altool.dll' + $alToolExists = Test-Path -Path $alToolDll -PathType Leaf + } } elseif ($isMacOS) { $alcPath = Join-Path $binPath 'darwin' - $alToolExe = Join-Path $alcPath 'altool' - Write-Host "Setting execute permissions on altool" - & chmod +x $alToolExe + $command = Join-Path $alcPath 'altool' + if (Test-Path $command) { + Write-Host "Setting execute permissions on altool" + & chmod +x $command + $alToolExists = $true + } + else { + Write-Host "No altool executable found. Using dotnet to run altool.dll." + $command = 'dotnet' + $alToolDll = Join-Path $alcPath 'altool.dll' + $alToolExists = Test-Path -Path $alToolDll -PathType Leaf + } } else { $alcPath = Join-Path $binPath 'win32' - $alToolExe = Join-Path $alcPath 'altool.exe' + $command = Join-Path $alcPath 'altool.exe' + $alToolExists = Test-Path -Path $command -PathType Leaf } if (-not (Test-Path $alcPath)) { $alcPath = $binPath } - $alToolExists = Test-Path -Path $alToolExe -PathType Leaf $alcDllPath = $alcPath if (!($isLinux -or $isMacOS) -and !$isPsCore) { $alcDllPath = $binPath @@ -1091,7 +1111,11 @@ function GetAppInfo { } else { if ($alToolExists) { - $manifest = CmdDo -Command $alToolExe -arguments @('GetPackageManifest', """$path""") -returnValue -silent | ConvertFrom-Json + $arguments = @('GetPackageManifest', """$path""") + if ($alToolDll) { + $arguments = @($alToolDll) + $arguments + } + $manifest = CmdDo -Command $command -arguments $arguments -returnValue -silent | ConvertFrom-Json $appInfo = @{ "appId" = $manifest.id "publisher" = $manifest.publisher @@ -1280,18 +1304,33 @@ function RunAlTool { ) $path = DownloadLatestAlLanguageExtension -allowPrerelease:$usePrereleaseAlTool if ($isLinux) { - $alToolExe = Join-Path $path 'extension/bin/linux/altool' - & /usr/bin/env sudo pwsh -command "& chmod +x $alToolExe" + $command = Join-Path $path 'extension/bin/linux/altool' + if (Test-Path $command) { + Write-Host "Setting execute permissions on altool" + & /usr/bin/env sudo pwsh -command "& chmod +x $command" + } + else { + Write-Host "No altool executable found. Using dotnet to run altool.dll." + $command = 'dotnet' + $arguments = @(Join-Path $path 'extension/bin/linux/altool.dll') + $arguments + } } elseif ($isMacOS) { - $alToolExe = Join-Path $path 'extension/bin/darwin/altool' - Write-Host "Setting execute permissions on altool" - & chmod +x $alToolExe + $command = Join-Path $path 'extension/bin/darwin/altool' + if (Test-Path $command) { + Write-Host "Setting execute permissions on altool" + & chmod +x $command + } + else { + Write-Host "No altool executable found. Using dotnet to run altool.dll." + $command = 'dotnet' + $arguments = @(Join-Path $path 'extension/bin/darwin/altool.dll') + $arguments + } } else { - $alToolExe = Join-Path $path 'extension/bin/win32/altool.exe' + $command = Join-Path $path 'extension/bin/win32/altool.exe' } - CmdDo -Command $alToolExe -arguments $arguments -returnValue -silent + CmdDo -Command $command -arguments $arguments -returnValue -silent } function GetApplicationDependency( [string] $appFile, [string] $minVersion = "0.0" ) { diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index ce7449911..44e1b639f 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -2,6 +2,8 @@ Fix issue where generateDependencyArtifact doesn't result in dependencies if useCompilerFolder is true or filesonly containers are used in Run-AlPipeline Issue 3686 PowerShell container shortcuts for >= BC24 using wrong PowerShell version Issue 3666 Run-AlCops + Run-AlPipeline using outdated appsource default ruleset +Fix issue where linux executables are missing in the AL Language Extension (use dotnet to execute the commands instead) +Fix issue where PowerShell sometimes hangs when trying to establish a new PSSession shortly after removing another PSSession (Noticed during end 2 end tests on AL-Go for GitHub) 6.0.24 Use pre-release altool when running alcops (to be able to get runtime version of nextmajor)