Skip to content

Commit 1997c6d

Browse files
authored
Log all the modules and versions in the promoted snapshot (#344)
Log all the modules and versions in the promoted snapshot
1 parent 8cab08b commit 1997c6d

File tree

8 files changed

+139
-20
lines changed

8 files changed

+139
-20
lines changed

src/DependencyManagement/DependencyManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public DependencyManager(
5555
_installer = installer ?? new DependencySnapshotInstaller(
5656
moduleProvider ?? new PowerShellGalleryModuleProvider(),
5757
_storage,
58-
new PowerShellModuleSnapshotComparer());
58+
new PowerShellModuleSnapshotComparer(),
59+
new PowerShellModuleSnapshotLogger());
5960
_newerSnapshotDetector = newerSnapshotDetector ?? new NewerDependencySnapshotDetector(_storage, new WorkerRestarter());
6061
_backgroundSnapshotMaintainer =
6162
maintainer ?? new BackgroundDependencySnapshotMaintainer(

src/DependencyManagement/DependencySnapshotInstaller.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@ internal class DependencySnapshotInstaller : IDependencySnapshotInstaller
2222
private readonly IModuleProvider _moduleProvider;
2323
private readonly IDependencyManagerStorage _storage;
2424
private readonly IDependencySnapshotComparer _snapshotComparer;
25+
private readonly IDependencySnapshotContentLogger _snapshotContentLogger;
2526

2627
public DependencySnapshotInstaller(
2728
IModuleProvider moduleProvider,
2829
IDependencyManagerStorage storage,
29-
IDependencySnapshotComparer snapshotComparer)
30+
IDependencySnapshotComparer snapshotComparer,
31+
IDependencySnapshotContentLogger snapshotContentLogger)
3032
{
3133
_moduleProvider = moduleProvider ?? throw new ArgumentNullException(nameof(moduleProvider));
3234
_storage = storage ?? throw new ArgumentNullException(nameof(storage));
3335
_snapshotComparer = snapshotComparer ?? throw new ArgumentNullException(nameof(snapshotComparer));
36+
_snapshotContentLogger = snapshotContentLogger ?? throw new ArgumentNullException(nameof(snapshotContentLogger));
3437
}
3538

3639
public void InstallSnapshot(
@@ -75,6 +78,8 @@ public void InstallSnapshot(
7578
isUserOnlyLog: false,
7679
LogLevel.Trace,
7780
string.Format(PowerShellWorkerStrings.PromotedDependencySnapshot, installingPath, targetPath));
81+
82+
_snapshotContentLogger.LogDependencySnapshotContent(targetPath, logger);
7883
}
7984
}
8085
catch (Exception e)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement
7+
{
8+
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
9+
10+
internal interface IDependencySnapshotContentLogger
11+
{
12+
void LogDependencySnapshotContent(string snapshotPath, ILogger logger);
13+
}
14+
}

src/DependencyManagement/PowerShellModuleSnapshotComparer.cs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public bool AreEquivalent(string snapshotPathA, string snapshotPathB, ILogger lo
3232
{
3333
try
3434
{
35-
var versionSubdirsA = GetModuleVersionSubdirectories(snapshotPathA);
36-
var versionSubdirsB = GetModuleVersionSubdirectories(snapshotPathB);
35+
var versionSubdirsA = PowerShellModuleSnapshotTools.GetModuleVersionSubdirectories(snapshotPathA, _getSubdirectories);
36+
var versionSubdirsB = PowerShellModuleSnapshotTools.GetModuleVersionSubdirectories(snapshotPathB, _getSubdirectories);
3737
return versionSubdirsA.SequenceEqual(versionSubdirsB);
3838
}
3939
catch (IOException e)
@@ -50,20 +50,5 @@ public bool AreEquivalent(string snapshotPathA, string snapshotPathB, ILogger lo
5050
return false;
5151
}
5252
}
53-
54-
private IEnumerable<string> GetModuleVersionSubdirectories(string snapshotPath)
55-
{
56-
var modulePaths = _getSubdirectories(snapshotPath).ToList();
57-
modulePaths.Sort();
58-
foreach (var modulePath in modulePaths)
59-
{
60-
var versionPaths = _getSubdirectories(modulePath).ToList();
61-
versionPaths.Sort();
62-
foreach (var versionPath in versionPaths)
63-
{
64-
yield return Path.Join(Path.GetFileName(modulePath), Path.GetFileName(versionPath));
65-
}
66-
}
67-
}
6853
}
6954
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement
7+
{
8+
using System;
9+
using System.IO;
10+
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
11+
12+
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
13+
14+
internal class PowerShellModuleSnapshotLogger : IDependencySnapshotContentLogger
15+
{
16+
public void LogDependencySnapshotContent(string snapshotPath, ILogger logger)
17+
{
18+
try
19+
{
20+
var moduleVersionSubdirectories = PowerShellModuleSnapshotTools.GetModuleVersionSubdirectories(snapshotPath);
21+
22+
foreach (var moduleVersionSubdirectory in moduleVersionSubdirectories)
23+
{
24+
// Module version subdirectories follow the following pattern: <snapshotPath>\<module name>\<module version>
25+
var moduleName = Path.GetFileName(Path.GetDirectoryName(moduleVersionSubdirectory));
26+
var moduleVersion = Path.GetFileName(moduleVersionSubdirectory);
27+
var snapshotName = Path.GetFileName(snapshotPath);
28+
29+
var message = string.Format(PowerShellWorkerStrings.DependencyShapshotContent, snapshotName, moduleName, moduleVersion);
30+
logger.Log(isUserOnlyLog: false, LogLevel.Trace, message);
31+
}
32+
}
33+
catch (Exception e) when (e is IOException || e is UnauthorizedAccessException)
34+
{
35+
var message = string.Format(PowerShellWorkerStrings.FailedToEnumerateDependencySnapshotContent, snapshotPath, e.Message);
36+
logger.Log(isUserOnlyLog: false, LogLevel.Warning, message);
37+
}
38+
}
39+
}
40+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.Azure.Functions.PowerShellWorker.DependencyManagement
7+
{
8+
using System;
9+
using System.Collections.Generic;
10+
using System.IO;
11+
using System.Linq;
12+
13+
internal class PowerShellModuleSnapshotTools
14+
{
15+
/// <summary>
16+
/// Returns all module version subdirectories, assuming that the directory structure follows
17+
/// regular PowerShell conventions.
18+
///
19+
/// For example, if PowerShell modules are installed into the "C:\Modules" directory
20+
/// and the content of this directory looks like this:
21+
///
22+
/// C:\
23+
/// Modules\
24+
/// ModuleA\
25+
/// 1.0\
26+
/// ...
27+
/// 2.1\
28+
/// ...
29+
/// ModuleB\
30+
/// 1.3.2\
31+
/// ...
32+
/// then GetModuleVersionSubdirectories("C:\Modules") will return the following strings:
33+
///
34+
/// C:\Modules\ModuleA\1.0
35+
/// C:\Modules\ModuleA\2.1
36+
/// C:\Modules\ModuleB\1.3.2
37+
///
38+
/// </summary>
39+
public static IEnumerable<string> GetModuleVersionSubdirectories(string snapshotPath)
40+
{
41+
return GetModuleVersionSubdirectories(snapshotPath, Directory.EnumerateDirectories);
42+
}
43+
44+
public static IEnumerable<string> GetModuleVersionSubdirectories(
45+
string snapshotPath,
46+
Func<string, IEnumerable<string>> getSubdirectories)
47+
{
48+
var modulePaths = getSubdirectories(snapshotPath).ToList();
49+
modulePaths.Sort();
50+
foreach (var modulePath in modulePaths)
51+
{
52+
var versionPaths = getSubdirectories(modulePath).ToList();
53+
versionPaths.Sort();
54+
foreach (var versionPath in versionPaths)
55+
{
56+
yield return Path.Join(Path.GetFileName(modulePath), Path.GetFileName(versionPath));
57+
}
58+
}
59+
}
60+
}
61+
}

src/resources/PowerShellWorkerStrings.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,10 @@
292292
<data name="FunctionInvocationStarting" xml:space="preserve">
293293
<value>Invoking function '{0}' code {1} ms after receiving request. Invocation performance details: {2}</value>
294294
</data>
295+
<data name="DependencyShapshotContent" xml:space="preserve">
296+
<value>Dependency snapshot '{0}' contains module '{1}' version '{2}'.</value>
297+
</data>
298+
<data name="FailedToEnumerateDependencySnapshotContent" xml:space="preserve">
299+
<value>Failed to enumerate dependency snapshot '{0}' content: {1}</value>
300+
</data>
295301
</root>

test/Unit/DependencyManagement/DependencySnapshotInstallerTests.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class DependencySnapshotInstallerTests
2323
private readonly Mock<IModuleProvider> _mockModuleProvider = new Mock<IModuleProvider>();
2424
private readonly Mock<IDependencyManagerStorage> _mockStorage = new Mock<IDependencyManagerStorage>(MockBehavior.Strict);
2525
private readonly Mock<IDependencySnapshotComparer> _mockSnapshotComparer = new Mock<IDependencySnapshotComparer>(MockBehavior.Strict);
26+
private readonly Mock<IDependencySnapshotContentLogger> _mockSnapshotContentLogger = new Mock<IDependencySnapshotContentLogger>();
2627
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
2728

2829
private readonly string _targetPathInstalled;
@@ -94,6 +95,7 @@ public void PromotesInstallingSnapshotToInstalledIfSaveModuleDoesNotThrow()
9495

9596
_mockStorage.Verify(_ => _.CreateInstallingSnapshot(_targetPathInstalled), Times.Once);
9697
_mockStorage.Verify(_ => _.PromoteInstallingSnapshotToInstalledAtomically(_targetPathInstalled), Times.Once);
98+
_mockSnapshotContentLogger.Verify(_ => _.LogDependencySnapshotContent(_targetPathInstalled, _mockLogger.Object), Times.Once);
9799
}
98100

99101
[Fact]
@@ -110,6 +112,7 @@ public void PromotesInstallingSnapshotToInstalledIfNotEquivalentToLatest()
110112

111113
_mockStorage.Verify(_ => _.CreateInstallingSnapshot(_targetPathInstalled), Times.Once);
112114
_mockStorage.Verify(_ => _.PromoteInstallingSnapshotToInstalledAtomically(_targetPathInstalled), Times.Once);
115+
_mockSnapshotContentLogger.Verify(_ => _.LogDependencySnapshotContent(_targetPathInstalled, _mockLogger.Object), Times.Once);
113116
}
114117

115118
[Fact]
@@ -230,7 +233,11 @@ public void DoesNotPromoteSnapshotIfItIsEquivalentToLatest()
230233

231234
private DependencySnapshotInstaller CreateDependenciesSnapshotInstallerWithMocks()
232235
{
233-
return new DependencySnapshotInstaller(_mockModuleProvider.Object, _mockStorage.Object, _mockSnapshotComparer.Object);
236+
return new DependencySnapshotInstaller(
237+
_mockModuleProvider.Object,
238+
_mockStorage.Object,
239+
_mockSnapshotComparer.Object,
240+
_mockSnapshotContentLogger.Object);
234241
}
235242

236243
private void VerifyLoggedOnce(IEnumerable<string> messageParts)

0 commit comments

Comments
 (0)