Skip to content

Commit fc3e1d1

Browse files
Disable automatic module upgrades for PowerShell 7.0 function apps (#956)
* 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
1 parent 6ed9485 commit fc3e1d1

File tree

5 files changed

+66
-28
lines changed

5 files changed

+66
-28
lines changed

src/DependencyManagement/BackgroundDependencySnapshotMaintainer.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ internal class BackgroundDependencySnapshotMaintainer : IBackgroundDependencySna
2020
private TimeSpan MaxBackgroundUpgradePeriod { get; } =
2121
PowerShellWorkerConfiguration.GetTimeSpan("MDMaxBackgroundUpgradePeriod") ?? TimeSpan.FromDays(7);
2222

23+
private bool EnableAutomaticUpgrades { get; } =
24+
PowerShellWorkerConfiguration.GetBoolean("MDEnableAutomaticUpgrades") ?? false;
25+
2326
private readonly IDependencyManagerStorage _storage;
2427
private readonly IDependencySnapshotInstaller _installer;
2528
private readonly IDependencySnapshotPurger _purger;
@@ -42,6 +45,16 @@ public void Start(string currentSnapshotPath, DependencyManifestEntry[] dependen
4245

4346
_purger.SetCurrentlyUsedSnapshot(currentSnapshotPath, logger);
4447

48+
if (!EnableAutomaticUpgrades)
49+
{
50+
logger.Log(
51+
isUserOnlyLog: false,
52+
RpcLog.Types.Level.Warning,
53+
PowerShellWorkerStrings.AutomaticUpgradesAreDisabled);
54+
55+
return;
56+
}
57+
4558
_installAndPurgeTimer = new Timer(
4659
_ => InstallAndPurgeSnapshots(PowerShell.Create, logger),
4760
state: null,

src/DependencyManagement/DependencyManager.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ internal class DependencyManager : IDisposable
4141

4242
private Task _dependencyInstallationTask;
4343

44+
private bool EnableAutomaticUpgrades { get; } =
45+
PowerShellWorkerConfiguration.GetBoolean("MDEnableAutomaticUpgrades") ?? false;
46+
4447
#endregion
4548

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

205+
if (!EnableAutomaticUpgrades)
206+
{
207+
logger.Log(
208+
isUserOnlyLog: false,
209+
RpcLog.Types.Level.Warning,
210+
PowerShellWorkerStrings.AutomaticUpgradesAreDisabled);
211+
212+
return null;
213+
}
214+
202215
// Background installation: can't use the firstPwsh runspace because it belongs
203216
// to the pool used to run functions code, so create a new runspace.
204217
_nextSnapshotPath = _backgroundSnapshotMaintainer.InstallAndPurgeSnapshots(pwshFactory, logger);

src/resources/PowerShellWorkerStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,4 +352,7 @@
352352
<data name="DependencySnapshotDoesNotContainAcceptableModuleVersions" xml:space="preserve">
353353
<value>Dependency snapshot '{0}' does not contain acceptable module versions.</value>
354354
</data>
355+
<data name="AutomaticUpgradesAreDisabled" xml:space="preserve">
356+
<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>
357+
</data>
355358
</root>

test/Unit/DependencyManagement/DependencyManagerTests.cs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -163,40 +163,49 @@ public void StartDependencyInstallationIfNeeded_InstallsSnapshotInForeground_Whe
163163
[Fact]
164164
public void StartDependencyInstallationIfNeeded_InvokesBackgroundMaintainer_WhenAcceptableDependenciesAlreadyInstalled()
165165
{
166-
_mockInstalledDependenciesLocator.Setup(_ => _.GetPathWithAcceptableDependencyVersionsInstalled())
167-
.Returns("AlreadyInstalled");
168-
_mockStorage.Setup(_ => _.GetDependencies()).Returns(GetAnyNonEmptyDependencyManifestEntries());
166+
try
167+
{
168+
Environment.SetEnvironmentVariable("MDEnableAutomaticUpgrades", "true");
169169

170-
var firstPowerShellRunspace = PowerShell.Create();
171-
Func<PowerShell> powerShellFactory = PowerShell.Create;
170+
_mockInstalledDependenciesLocator.Setup(_ => _.GetPathWithAcceptableDependencyVersionsInstalled())
171+
.Returns("AlreadyInstalled");
172+
_mockStorage.Setup(_ => _.GetDependencies()).Returns(GetAnyNonEmptyDependencyManifestEntries());
172173

173-
_mockStorage.Setup(_ => _.SnapshotExists("AlreadyInstalled")).Returns(true);
174+
var firstPowerShellRunspace = PowerShell.Create();
175+
Func<PowerShell> powerShellFactory = PowerShell.Create;
174176

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

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

185-
Assert.False(hadToWait);
186-
Assert.Equal("NewSnapshot", dependencyManager.WaitForBackgroundDependencyInstallationTaskCompletion());
183+
using (var dependencyManager = CreateDependencyManagerWithMocks())
184+
{
185+
dependencyManager.Initialize(_mockLogger.Object);
186+
dependencyManager.StartDependencyInstallationIfNeeded(firstPowerShellRunspace, powerShellFactory, _mockLogger.Object);
187+
var hadToWait = dependencyManager.WaitForDependenciesAvailability(() => _mockLogger.Object);
187188

188-
_mockBackgroundDependencySnapshotMaintainer.Verify(
189-
_ => _.InstallAndPurgeSnapshots(powerShellFactory, _mockLogger.Object),
189+
Assert.False(hadToWait);
190+
Assert.Equal("NewSnapshot", dependencyManager.WaitForBackgroundDependencyInstallationTaskCompletion());
191+
192+
_mockBackgroundDependencySnapshotMaintainer.Verify(
193+
_ => _.InstallAndPurgeSnapshots(powerShellFactory, _mockLogger.Object),
194+
Times.Once);
195+
}
196+
197+
_mockLogger.Verify(
198+
_ => _.Log(
199+
false,
200+
LogLevel.Trace,
201+
It.Is<string>(message => message.Contains(PowerShellWorkerStrings.AcceptableFunctionAppDependenciesAlreadyInstalled)),
202+
It.IsAny<Exception>()),
190203
Times.Once);
191204
}
192-
193-
_mockLogger.Verify(
194-
_ => _.Log(
195-
false,
196-
LogLevel.Trace,
197-
It.Is<string>(message => message.Contains(PowerShellWorkerStrings.AcceptableFunctionAppDependenciesAlreadyInstalled)),
198-
It.IsAny<Exception>()),
199-
Times.Once);
205+
finally
206+
{
207+
Environment.SetEnvironmentVariable("MDEnableAutomaticUpgrades", null);
208+
}
200209
}
201210

202211
[Fact]

tools/helper.psm1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ function Install-Dotnet {
7474
$version = "$majorMinorVersion.$($DotnetSDKVersionRequirements[$majorMinorVersion].DefaultPatch)"
7575
Write-Log "Installing dotnet SDK version $version" -Warning
7676
if ($IsWindowsEnv) {
77-
& .\$installScript -Channel $Channel -Version $Version
77+
& .\$installScript -Channel $Channel -Version $Version -InstallDir "$env:ProgramFiles/dotnet"
7878
} else {
79-
bash ./$installScript -c $Channel -v $Version
79+
bash ./$installScript -c $Channel -v $Version --install-dir /usr/share/dotnet
8080
}
8181
}
8282

0 commit comments

Comments
 (0)