Skip to content

Commit 0c494c0

Browse files
Disable optional upgrades in PowerShell function apps (#779)
* Add AutomaticUpgradesAreDisabled message * Disable optional upgrades * Update test
1 parent 9fa9653 commit 0c494c0

File tree

4 files changed

+64
-26
lines changed

4 files changed

+64
-26
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(
@@ -198,6 +201,16 @@ internal Exception InstallFunctionAppDependencies(PowerShell firstPwsh, Func<Pow
198201
RpcLog.Types.Level.Trace,
199202
PowerShellWorkerStrings.AcceptableFunctionAppDependenciesAlreadyInstalled);
200203

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

src/resources/PowerShellWorkerStrings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,7 @@
322322
<data name="PowerShell6EndOfLifeWarning" xml:space="preserve">
323323
<value>The Function app uses PowerShell Core 6. Your Function app is still supported, but this version of PowerShell reached end of life, so it is strongly recommended that you migrate the Function app to PowerShell 7. For more details, see https://aka.ms/functions-powershell-6-to-7.</value>
324324
</data>
325+
<data name="AutomaticUpgradesAreDisabled" xml:space="preserve">
326+
<value>Automatic upgrades are disabled in PowerShell 6 function apps. To enable this functionality back, please migrate your function app to PowerShell 7. For more details, see https://aka.ms/functions-powershell-6-to-7.</value>
327+
</data>
325328
</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]

0 commit comments

Comments
 (0)