Skip to content

Commit

Permalink
Disable automatic module upgrades for PowerShell 7.0 function apps (#956
Browse files Browse the repository at this point in the history
)

* Disable optional upgrades in PowerShell function apps (#779)

* Add AutomaticUpgradesAreDisabled message

* Disable optional upgrades

* Update test

* Update upgrade guidance for PowerShell 7.0 function apps

* Add installation directory for the .Net SDK
  • Loading branch information
Francisco-Gamino authored May 15, 2023
1 parent 6ed9485 commit fc3e1d1
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 28 deletions.
13 changes: 13 additions & 0 deletions src/DependencyManagement/BackgroundDependencySnapshotMaintainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ internal class BackgroundDependencySnapshotMaintainer : IBackgroundDependencySna
private TimeSpan MaxBackgroundUpgradePeriod { get; } =
PowerShellWorkerConfiguration.GetTimeSpan("MDMaxBackgroundUpgradePeriod") ?? TimeSpan.FromDays(7);

private bool EnableAutomaticUpgrades { get; } =
PowerShellWorkerConfiguration.GetBoolean("MDEnableAutomaticUpgrades") ?? false;

private readonly IDependencyManagerStorage _storage;
private readonly IDependencySnapshotInstaller _installer;
private readonly IDependencySnapshotPurger _purger;
Expand All @@ -42,6 +45,16 @@ public void Start(string currentSnapshotPath, DependencyManifestEntry[] dependen

_purger.SetCurrentlyUsedSnapshot(currentSnapshotPath, logger);

if (!EnableAutomaticUpgrades)
{
logger.Log(
isUserOnlyLog: false,
RpcLog.Types.Level.Warning,
PowerShellWorkerStrings.AutomaticUpgradesAreDisabled);

return;
}

_installAndPurgeTimer = new Timer(
_ => InstallAndPurgeSnapshots(PowerShell.Create, logger),
state: null,
Expand Down
13 changes: 13 additions & 0 deletions src/DependencyManagement/DependencyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ internal class DependencyManager : IDisposable

private Task _dependencyInstallationTask;

private bool EnableAutomaticUpgrades { get; } =
PowerShellWorkerConfiguration.GetBoolean("MDEnableAutomaticUpgrades") ?? false;

#endregion

public DependencyManager(
Expand Down Expand Up @@ -199,6 +202,16 @@ internal Exception InstallFunctionAppDependencies(PowerShell firstPwsh, Func<Pow
RpcLog.Types.Level.Trace,
PowerShellWorkerStrings.AcceptableFunctionAppDependenciesAlreadyInstalled);

if (!EnableAutomaticUpgrades)
{
logger.Log(
isUserOnlyLog: false,
RpcLog.Types.Level.Warning,
PowerShellWorkerStrings.AutomaticUpgradesAreDisabled);

return null;
}

// Background installation: can't use the firstPwsh runspace because it belongs
// to the pool used to run functions code, so create a new runspace.
_nextSnapshotPath = _backgroundSnapshotMaintainer.InstallAndPurgeSnapshots(pwshFactory, logger);
Expand Down
3 changes: 3 additions & 0 deletions src/resources/PowerShellWorkerStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,7 @@
<data name="DependencySnapshotDoesNotContainAcceptableModuleVersions" xml:space="preserve">
<value>Dependency snapshot '{0}' does not contain acceptable module versions.</value>
</data>
<data name="AutomaticUpgradesAreDisabled" xml:space="preserve">
<value>Automatic upgrades are disabled in PowerShell 7.0 function apps. To enable this functionality back, please migrate your function app to PowerShell 7.2. For more details, see https://aka.ms/functions-powershell-7.0-to-7.2.</value>
</data>
</root>
61 changes: 35 additions & 26 deletions test/Unit/DependencyManagement/DependencyManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,40 +163,49 @@ public void StartDependencyInstallationIfNeeded_InstallsSnapshotInForeground_Whe
[Fact]
public void StartDependencyInstallationIfNeeded_InvokesBackgroundMaintainer_WhenAcceptableDependenciesAlreadyInstalled()
{
_mockInstalledDependenciesLocator.Setup(_ => _.GetPathWithAcceptableDependencyVersionsInstalled())
.Returns("AlreadyInstalled");
_mockStorage.Setup(_ => _.GetDependencies()).Returns(GetAnyNonEmptyDependencyManifestEntries());
try
{
Environment.SetEnvironmentVariable("MDEnableAutomaticUpgrades", "true");

var firstPowerShellRunspace = PowerShell.Create();
Func<PowerShell> powerShellFactory = PowerShell.Create;
_mockInstalledDependenciesLocator.Setup(_ => _.GetPathWithAcceptableDependencyVersionsInstalled())
.Returns("AlreadyInstalled");
_mockStorage.Setup(_ => _.GetDependencies()).Returns(GetAnyNonEmptyDependencyManifestEntries());

_mockStorage.Setup(_ => _.SnapshotExists("AlreadyInstalled")).Returns(true);
var firstPowerShellRunspace = PowerShell.Create();
Func<PowerShell> powerShellFactory = PowerShell.Create;

_mockBackgroundDependencySnapshotMaintainer.Setup(
_ => _.InstallAndPurgeSnapshots(It.IsAny<Func<PowerShell>>(), It.IsAny<ILogger>()))
.Returns("NewSnapshot");
_mockStorage.Setup(_ => _.SnapshotExists("AlreadyInstalled")).Returns(true);

using (var dependencyManager = CreateDependencyManagerWithMocks())
{
dependencyManager.Initialize(_mockLogger.Object);
dependencyManager.StartDependencyInstallationIfNeeded(firstPowerShellRunspace, powerShellFactory, _mockLogger.Object);
var hadToWait = dependencyManager.WaitForDependenciesAvailability(() => _mockLogger.Object);
_mockBackgroundDependencySnapshotMaintainer.Setup(
_ => _.InstallAndPurgeSnapshots(It.IsAny<Func<PowerShell>>(), It.IsAny<ILogger>()))
.Returns("NewSnapshot");

Assert.False(hadToWait);
Assert.Equal("NewSnapshot", dependencyManager.WaitForBackgroundDependencyInstallationTaskCompletion());
using (var dependencyManager = CreateDependencyManagerWithMocks())
{
dependencyManager.Initialize(_mockLogger.Object);
dependencyManager.StartDependencyInstallationIfNeeded(firstPowerShellRunspace, powerShellFactory, _mockLogger.Object);
var hadToWait = dependencyManager.WaitForDependenciesAvailability(() => _mockLogger.Object);

_mockBackgroundDependencySnapshotMaintainer.Verify(
_ => _.InstallAndPurgeSnapshots(powerShellFactory, _mockLogger.Object),
Assert.False(hadToWait);
Assert.Equal("NewSnapshot", dependencyManager.WaitForBackgroundDependencyInstallationTaskCompletion());

_mockBackgroundDependencySnapshotMaintainer.Verify(
_ => _.InstallAndPurgeSnapshots(powerShellFactory, _mockLogger.Object),
Times.Once);
}

_mockLogger.Verify(
_ => _.Log(
false,
LogLevel.Trace,
It.Is<string>(message => message.Contains(PowerShellWorkerStrings.AcceptableFunctionAppDependenciesAlreadyInstalled)),
It.IsAny<Exception>()),
Times.Once);
}

_mockLogger.Verify(
_ => _.Log(
false,
LogLevel.Trace,
It.Is<string>(message => message.Contains(PowerShellWorkerStrings.AcceptableFunctionAppDependenciesAlreadyInstalled)),
It.IsAny<Exception>()),
Times.Once);
finally
{
Environment.SetEnvironmentVariable("MDEnableAutomaticUpgrades", null);
}
}

[Fact]
Expand Down
4 changes: 2 additions & 2 deletions tools/helper.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ function Install-Dotnet {
$version = "$majorMinorVersion.$($DotnetSDKVersionRequirements[$majorMinorVersion].DefaultPatch)"
Write-Log "Installing dotnet SDK version $version" -Warning
if ($IsWindowsEnv) {
& .\$installScript -Channel $Channel -Version $Version
& .\$installScript -Channel $Channel -Version $Version -InstallDir "$env:ProgramFiles/dotnet"
} else {
bash ./$installScript -c $Channel -v $Version
bash ./$installScript -c $Channel -v $Version --install-dir /usr/share/dotnet
}
}

Expand Down

0 comments on commit fc3e1d1

Please sign in to comment.