commit 39b8b5a9c189c124c9d9fda3f139f19feeb51e71 parent d5267769cc459c4df1b5a25b40583976d21ed3a6 Author: JohnMcPMS <johnmcp@microsoft.com> Date: Mon, 14 Apr 2025 09:49:45 -0700 DSC v3 adapter support (#5302) ## Change If we don't find a resource in DSC v3 at the top level, look in all of the adapters for it. `dsc.exe` does this automatically when using the resource, so we only need to do it when finding the resource details. Also improves the diagnostics handling and fixes an issue with the type of `implementedAs`. ## Validation Adds an E2E test that uses the test v2 resource through the v3 processor. Diffstat:
14 files changed, 224 insertions(+), 100 deletions(-)
diff --git a/src/AppInstallerCLIE2ETests/ConfigureCommand.cs b/src/AppInstallerCLIE2ETests/ConfigureCommand.cs @@ -348,6 +348,24 @@ namespace AppInstallerCLIE2ETests Assert.True(exportText.Contains(propertyValue2)); } + /// <summary> + /// Simple test to confirm that a resource with a module specified can be discovered in a local repository that doesn't support resource discovery. + /// </summary> + [Test] + public void ConfigureFromTestRepo_DSCv3() + { + TestCommon.EnsureModuleState(Constants.SimpleTestModuleName, present: true, repository: Constants.TestRepoName); + this.DeleteResourceArtifacts(); + + var result = TestCommon.RunAICLICommand(CommandAndAgreementsAndVerbose, TestCommon.GetTestDataFile("Configuration\\Configure_TestRepo_DSCv3.yml"), timeOut: 300000); + Assert.AreEqual(0, result.ExitCode); + + // The configuration creates a file next to itself with the given contents + string targetFilePath = TestCommon.GetTestDataFile("Configuration\\Configure_TestRepo.txt"); + FileAssert.Exists(targetFilePath); + Assert.AreEqual("Contents!", File.ReadAllText(targetFilePath)); + } + private void DeleteResourceArtifacts() { // Delete all .txt files in the test directory; they are placed there by the tests diff --git a/src/AppInstallerCLIE2ETests/Helpers/TestCommon.cs b/src/AppInstallerCLIE2ETests/Helpers/TestCommon.cs @@ -806,6 +806,8 @@ namespace AppInstallerCLIE2ETests.Helpers isPresent = e2eModule.Any(); } + TestContext.Out.WriteLine($"EnsureModuleState: {moduleName}[present:{present}] => isPresent:{isPresent}"); + if (isPresent) { // If the module was saved in a different location we can't Uninstall-Module. @@ -819,6 +821,7 @@ namespace AppInstallerCLIE2ETests.Helpers if (!present) { + TestContext.Out.WriteLine($"EnsureModuleState: Removing {moduleName} to match present=false"); Directory.Delete(moduleBase, true); } else @@ -827,6 +830,7 @@ namespace AppInstallerCLIE2ETests.Helpers var expectedLocation = TestCommon.GetExpectedModulePath(location); if (!moduleBase.StartsWith(expectedLocation)) { + TestContext.Out.WriteLine($"EnsureModuleState: Removing {moduleName} as it is not in the correct location"); Directory.Delete(moduleBase, true); isPresent = false; } @@ -848,11 +852,16 @@ namespace AppInstallerCLIE2ETests.Helpers pwsh.PowerShell.AddParameter("Repository", repository); } - if (location == TestModuleLocation.AllUsers) + if (location == TestModuleLocation.CurrentUser) + { + pwsh.PowerShell.AddParameter("Scope", "CurrentUser"); + } + else if (location == TestModuleLocation.AllUsers) { pwsh.PowerShell.AddParameter("Scope", "AllUsers"); } + TestContext.Out.WriteLine($"EnsureModuleState: Installing module {moduleName} to {location}"); _ = pwsh.PowerShell.Invoke(); } else @@ -873,6 +882,7 @@ namespace AppInstallerCLIE2ETests.Helpers pwsh.PowerShell.AddParameter("Repository", repository); } + TestContext.Out.WriteLine($"EnsureModuleState: Saving module {moduleName} to {path}"); _ = pwsh.PowerShell.Invoke(); } } @@ -1124,9 +1134,9 @@ namespace AppInstallerCLIE2ETests.Helpers TestContext.Error.WriteLine("Command run error. Error: " + result.StdErr); } - if (TestSetup.Parameters.VerboseLogging && !string.IsNullOrEmpty(result.StdOut)) + if (TestSetup.Parameters.VerboseLogging) { - TestContext.Out.WriteLine("Command run output. Output:\n" + result.StdOut); + TestContext.Out.WriteLine("Command run output. Output:\n" + result.StdOut ?? "<null>"); } } else if (throwOnTimeout) diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/Configure_TestRepo_DSCv3.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/Configure_TestRepo_DSCv3.yml @@ -0,0 +1,10 @@ +$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json +metadata: + winget: + processor: dscv3 +resources: + - name: Test File + type: xE2ETestResource/E2EFileResource + properties: + Path: ${WinGetConfigRoot}\Configure_TestRepo.txt + Content: Contents! diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Helpers/ProcessorSettings.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Helpers/ProcessorSettings.cs @@ -7,9 +7,11 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers { using System; + using System.Collections.Generic; using System.IO; using System.Text; using Microsoft.Management.Configuration.Processor.DSCv3.Model; + using Microsoft.Management.Configuration.Processor.Helpers; /// <summary> /// Contains settings for the DSC v3 processor components to share. @@ -24,6 +26,8 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers private IDSCv3? dscV3 = null; private string? defaultPath = null; + private Dictionary<string, ResourceDetails> resourceDetailsDictionary = new (); + /// <summary> /// Gets or sets the path to the DSC v3 executable. /// </summary> @@ -99,6 +103,11 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers } /// <summary> + /// Gets or sets the diagnostics sink to use. + /// </summary> + public IDiagnosticsSink? DiagnosticsSink { get; set; } = null; + + /// <summary> /// Gets or sets a value indicating whether the processor should produce more verbose output. /// </summary> public bool DiagnosticTraceEnabled { get; set; } = false; @@ -131,6 +140,8 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers { ProcessorSettings result = new ProcessorSettings(); + result.resourceDetailsDictionary = this.resourceDetailsDictionary; + result.DiagnosticsSink = this.DiagnosticsSink; result.DscExecutablePath = this.DscExecutablePath; result.DiagnosticTraceEnabled = this.DiagnosticTraceEnabled; #if !AICLI_DISABLE_TEST_HOOKS @@ -157,6 +168,47 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers return sb.ToString(); } + /// <summary> + /// Gets the ResourceDetails for a configuration unit. + /// </summary> + /// <param name="configurationUnitInternal">The configuration unit to find details for.</param> + /// <param name="detailFlags">The level of detail to get.</param> + /// <returns>The ResourceDetails for the unit, or null if not found.</returns> + public ResourceDetails? GetResourceDetails(ConfigurationUnitInternal configurationUnitInternal, ConfigurationUnitDetailFlags detailFlags) + { + ResourceDetails? result = null; + bool inDictionary = false; + + lock (this.resourceDetailsDictionary) + { + inDictionary = this.resourceDetailsDictionary.TryGetValue(configurationUnitInternal.QualifiedName, out result); + } + + if (result == null) + { + result = new ResourceDetails(configurationUnitInternal); + } + + result.EnsureDetails(this, detailFlags); + + if (result.Exists) + { + if (!inDictionary) + { + lock (this.resourceDetailsDictionary) + { + this.resourceDetailsDictionary.Add(configurationUnitInternal.QualifiedName, result); + } + } + + return result; + } + else + { + return null; + } + } + private static string? GetDscExecutablePathForPackage(string packageFamilyName) { string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Model/IDSCv3.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Model/IDSCv3.cs @@ -30,40 +30,35 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Model /// Gets a single resource by its type name. /// </summary> /// <param name="resourceType">The type name of the resource.</param> - /// <param name="diagnosticsSink">The diagnostics sink if provided.</param> /// <returns>A single resource item.</returns> - public IResourceListItem? GetResourceByType(string resourceType, IDiagnosticsSink? diagnosticsSink = null); + public IResourceListItem? GetResourceByType(string resourceType); /// <summary> /// Tests a configuration unit. /// </summary> /// <param name="unitInternal">The unit to test.</param> - /// <param name="diagnosticsSink">The diagnostics sink if provided.</param> /// <returns>A test result.</returns> - public IResourceTestItem TestResource(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null); + public IResourceTestItem TestResource(ConfigurationUnitInternal unitInternal); /// <summary> /// Gets a configuration unit settings. /// </summary> /// <param name="unitInternal">The unit to get.</param> - /// <param name="diagnosticsSink">The diagnostics sink if provided.</param> /// <returns>A get result.</returns> - public IResourceGetItem GetResourceSettings(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null); + public IResourceGetItem GetResourceSettings(ConfigurationUnitInternal unitInternal); /// <summary> /// Sets a configuration unit settings. /// </summary> /// <param name="unitInternal">The unit to set.</param> - /// <param name="diagnosticsSink">The diagnostics sink if provided.</param> /// <returns>A set result.</returns> - public IResourceSetItem SetResourceSettings(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null); + public IResourceSetItem SetResourceSettings(ConfigurationUnitInternal unitInternal); /// <summary> /// Exports configuration unit. /// </summary> /// <param name="unitInternal">The unit to export.</param> - /// <param name="diagnosticsSink">The diagnostics sink if provided.</param> /// <returns>A list of export results.</returns> - public IList<IResourceExportItem> ExportResource(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null); + public IList<IResourceExportItem> ExportResource(ConfigurationUnitInternal unitInternal); } } diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Model/ResourceKind.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Model/ResourceKind.cs @@ -33,8 +33,8 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Model Group, /// <summary> - /// An import resource. + /// An importer resource. /// </summary> - Import, + Importer, } } diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Schema_2024_04/DSCv3.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Schema_2024_04/DSCv3.cs @@ -55,26 +55,39 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 } /// <inheritdoc /> - public IResourceListItem? GetResourceByType(string resourceType, IDiagnosticsSink? diagnosticsSink = null) + public IResourceListItem? GetResourceByType(string resourceType) { - ProcessExecution processExecution = new ProcessExecution() + ResourceListItem? result = this.GetResourceByType(resourceType, null); + if (result != null) { - ExecutablePath = this.processorSettings.EffectiveDscExecutablePath, - Arguments = new[] { PlainTextTraces, this.DiagnosticTraceLevel, ResourceCommand, ListCommand, resourceType }, - }; + return result; + } - RunSynchronously(processExecution, diagnosticsSink); + // Check for this resource within adapters + List<ResourceListItem> results = new List<ResourceListItem>(); - if (processExecution.Output.Count > 1) + foreach (ResourceListItem resource in this.GetAllResources()) + { + if (resource.Kind == Definitions.ResourceKind.Adapter) + { + result = this.GetResourceByType(resourceType, resource.Type); + if (result != null) + { + results.Add(result); + } + } + } + + if (results.Count > 1) { throw new Exceptions.GetDscResourceMultipleMatches(resourceType, null); } - return GetOptionalSingleOutputLineAs<ResourceListItem>(processExecution); + return results.FirstOrDefault(); } /// <inheritdoc /> - public IResourceTestItem TestResource(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IResourceTestItem TestResource(ConfigurationUnitInternal unitInternal) { ProcessExecution processExecution = new ProcessExecution() { @@ -83,7 +96,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 Input = ConvertValueSetToJSON(unitInternal.GetExpandedSettings()), }; - if (RunSynchronously(processExecution, diagnosticsSink)) + if (this.RunSynchronously(processExecution)) { throw new Exceptions.InvokeDscResourceException(Exceptions.InvokeDscResourceException.Test, unitInternal.QualifiedName, null, processExecution.GetAllErrorLines()); } @@ -92,7 +105,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 } /// <inheritdoc /> - public IResourceGetItem GetResourceSettings(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IResourceGetItem GetResourceSettings(ConfigurationUnitInternal unitInternal) { ProcessExecution processExecution = new ProcessExecution() { @@ -101,7 +114,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 Input = ConvertValueSetToJSON(unitInternal.GetExpandedSettings()), }; - if (RunSynchronously(processExecution, diagnosticsSink)) + if (this.RunSynchronously(processExecution)) { throw new Exceptions.InvokeDscResourceException(Exceptions.InvokeDscResourceException.Get, unitInternal.QualifiedName, null, processExecution.GetAllErrorLines()); } @@ -110,7 +123,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 } /// <inheritdoc /> - public IResourceSetItem SetResourceSettings(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IResourceSetItem SetResourceSettings(ConfigurationUnitInternal unitInternal) { ProcessExecution processExecution = new ProcessExecution() { @@ -119,7 +132,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 Input = ConvertValueSetToJSON(unitInternal.GetExpandedSettings()), }; - if (RunSynchronously(processExecution, diagnosticsSink)) + if (this.RunSynchronously(processExecution)) { throw new Exceptions.InvokeDscResourceException(Exceptions.InvokeDscResourceException.Set, unitInternal.QualifiedName, null, processExecution.GetAllErrorLines()); } @@ -128,7 +141,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 } /// <inheritdoc /> - public IList<IResourceExportItem> ExportResource(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IList<IResourceExportItem> ExportResource(ConfigurationUnitInternal unitInternal) { // 3.0 can't handle input to export; 3.1 will fix that. ValueSet expandedSettings = unitInternal.GetExpandedSettings(); @@ -143,7 +156,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 Arguments = new[] { PlainTextTraces, this.DiagnosticTraceLevel, ResourceCommand, ExportCommand, ResourceParameter, unitInternal.QualifiedName }, }; - if (RunSynchronously(processExecution, diagnosticsSink)) + if (this.RunSynchronously(processExecution)) { throw new Exceptions.InvokeDscResourceException(Exceptions.InvokeDscResourceException.Export, unitInternal.QualifiedName, null, processExecution.GetAllErrorLines()); } @@ -151,23 +164,6 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 return ConfigurationDocument.CreateFrom(GetRequiredSingleOutputLineAsJSON(processExecution, Exceptions.InvokeDscResourceException.Set, unitInternal.QualifiedName), GetDefaultJsonOptions()).InterfaceResources; } - /// <summary> - /// Runs the process, waiting until it completes. - /// </summary> - /// <param name="processExecution">The process to run.</param> - /// <param name="diagnosticsSink">The diagnostics sink.</param> - /// <returns>True if the exit code was not 0.</returns> - private static bool RunSynchronously(ProcessExecution processExecution, IDiagnosticsSink? diagnosticsSink) - { - diagnosticsSink?.OnDiagnostics(DiagnosticLevel.Verbose, $"Starting process: {processExecution.CommandLine}"); - - processExecution.Start().WaitForExit(); - - diagnosticsSink?.OnDiagnostics(DiagnosticLevel.Verbose, $"Process exited with code: {processExecution.ExitCode}\n--- Output Stream ---\n{processExecution.GetAllOutputLines()}\n--- Error Stream ---\n{processExecution.GetAllErrorLines()}"); - - return processExecution.ExitCode != 0; - } - private static void ThrowOnMultipleOutputLines(ProcessExecution processExecution, string method, string resourceName) { if (processExecution.Output.Count > 1) @@ -194,6 +190,23 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 return JsonSerializer.Deserialize<T>(processExecution.Output.First(), GetDefaultJsonOptions()); } + private static List<T> GetOutputLinesAs<T>(ProcessExecution processExecution) + { + List<T> result = new List<T>(); + var options = GetDefaultJsonOptions(); + + foreach (string line in processExecution.Output) + { + T? lineObject = JsonSerializer.Deserialize<T>(line, options); + if (lineObject != null) + { + result.Add(lineObject); + } + } + + return result; + } + private static JsonDocument GetRequiredSingleOutputLineAsJSON(ProcessExecution processExecution, string method, string resourceName) { ThrowOnMultipleOutputLines(processExecution, method, resourceName); @@ -218,5 +231,52 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04 { return JsonSerializer.Serialize(valueSet.ToHashtable()); } + + /// <summary> + /// Runs the process, waiting until it completes. + /// </summary> + /// <param name="processExecution">The process to run.</param> + /// <returns>True if the exit code was not 0.</returns> + private bool RunSynchronously(ProcessExecution processExecution) + { + this.processorSettings.DiagnosticsSink?.OnDiagnostics(DiagnosticLevel.Verbose, $"Starting process: {processExecution.CommandLine}"); + + processExecution.Start().WaitForExit(); + + this.processorSettings.DiagnosticsSink?.OnDiagnostics(DiagnosticLevel.Verbose, $"Process exited with code: {processExecution.ExitCode}\n--- Output Stream ---\n{processExecution.GetAllOutputLines()}\n--- Error Stream ---\n{processExecution.GetAllErrorLines()}"); + + return processExecution.ExitCode != 0; + } + + private ResourceListItem? GetResourceByType(string resourceType, string? adapter) + { + ProcessExecution processExecution = new ProcessExecution() + { + ExecutablePath = this.processorSettings.EffectiveDscExecutablePath, + Arguments = new[] { PlainTextTraces, this.DiagnosticTraceLevel, ResourceCommand, ListCommand, adapter != null ? $"-a {adapter}" : string.Empty, resourceType }, + }; + + this.RunSynchronously(processExecution); + + if (processExecution.Output.Count > 1) + { + throw new Exceptions.GetDscResourceMultipleMatches(resourceType, null); + } + + return GetOptionalSingleOutputLineAs<ResourceListItem>(processExecution); + } + + private List<ResourceListItem> GetAllResources() + { + ProcessExecution processExecution = new ProcessExecution() + { + ExecutablePath = this.processorSettings.EffectiveDscExecutablePath, + Arguments = new[] { PlainTextTraces, this.DiagnosticTraceLevel, ResourceCommand, ListCommand }, + }; + + this.RunSynchronously(processExecution); + + return GetOutputLinesAs<ResourceListItem>(processExecution); + } } } diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Schema_2024_04/Definitions/ResourceKind.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Schema_2024_04/Definitions/ResourceKind.cs @@ -33,8 +33,15 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04.Defi Group, /// <summary> - /// An import resource. + /// An import(er) resource. + /// The name listed in the DSC schema. /// </summary> Import, + + /// <summary> + /// An importer resource. + /// The name used by the code. + /// </summary> + Importer = Import, } } diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Schema_2024_04/Outputs/ResourceListItem.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Schema_2024_04/Outputs/ResourceListItem.cs @@ -35,7 +35,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04.Outp Definitions.ResourceKind.Resource => Model.ResourceKind.Resource, Definitions.ResourceKind.Adapter => Model.ResourceKind.Adapter, Definitions.ResourceKind.Group => Model.ResourceKind.Group, - Definitions.ResourceKind.Import => Model.ResourceKind.Import, + Definitions.ResourceKind.Import => Model.ResourceKind.Importer, _ => throw new System.IO.InvalidDataException($"Unknown ResourceKind: {this.Kind}") }; @@ -69,7 +69,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Schema_2024_04.Outp /// <summary> /// Gets or sets a value that indicates implementation details of the resource. /// </summary> - public JsonObject? ImplementedAs { get; set; } + public JsonNode? ImplementedAs { get; set; } /// <summary> /// Gets or sets the author of the resource. diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Set/DSCv3ConfigurationSetProcessor.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Set/DSCv3ConfigurationSetProcessor.cs @@ -18,7 +18,6 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Set internal sealed partial class DSCv3ConfigurationSetProcessor : ConfigurationSetProcessorBase, IConfigurationSetProcessor { private readonly ProcessorSettings processorSettings; - private Dictionary<string, ResourceDetails> resourceDetailsDictionary = new (); /// <summary> /// Initializes a new instance of the <see cref="DSCv3ConfigurationSetProcessor"/> class. @@ -38,7 +37,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Set ConfigurationUnitInternal configurationUnitInternal = new ConfigurationUnitInternal(unit, this.ConfigurationSet?.Path); this.OnDiagnostics(DiagnosticLevel.Verbose, $"Creating unit processor for: {configurationUnitInternal.QualifiedName}..."); - ResourceDetails? resourceDetails = this.GetResourceDetails(configurationUnitInternal, ConfigurationUnitDetailFlags.Local); + ResourceDetails? resourceDetails = this.processorSettings.GetResourceDetails(configurationUnitInternal, ConfigurationUnitDetailFlags.Local); if (resourceDetails == null) { this.OnDiagnostics(DiagnosticLevel.Verbose, $"Resource not found: {configurationUnitInternal.QualifiedName}"); @@ -54,7 +53,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Set ConfigurationUnitInternal configurationUnitInternal = new ConfigurationUnitInternal(unit, this.ConfigurationSet?.Path); this.OnDiagnostics(DiagnosticLevel.Verbose, $"Getting resource details [{detailFlags}] for: {configurationUnitInternal.QualifiedName}..."); - ResourceDetails? resourceDetails = this.GetResourceDetails(configurationUnitInternal, detailFlags); + ResourceDetails? resourceDetails = this.processorSettings.GetResourceDetails(configurationUnitInternal, detailFlags); if (resourceDetails == null) { this.OnDiagnostics(DiagnosticLevel.Verbose, $"Resource not found: {configurationUnitInternal.QualifiedName}"); @@ -63,40 +62,5 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Set return resourceDetails.GetConfigurationUnitProcessorDetails(); } - - private ResourceDetails? GetResourceDetails(ConfigurationUnitInternal configurationUnitInternal, ConfigurationUnitDetailFlags detailFlags) - { - ResourceDetails? result = null; - bool inDictionary = false; - - lock (this.resourceDetailsDictionary) - { - inDictionary = this.resourceDetailsDictionary.TryGetValue(configurationUnitInternal.QualifiedName, out result); - } - - if (result == null) - { - result = new ResourceDetails(configurationUnitInternal); - } - - result.EnsureDetails(this.processorSettings, detailFlags); - - if (result.Exists) - { - if (!inDictionary) - { - lock (this.resourceDetailsDictionary) - { - this.resourceDetailsDictionary.Add(configurationUnitInternal.QualifiedName, result); - } - } - - return result; - } - else - { - return null; - } - } } } diff --git a/src/Microsoft.Management.Configuration.Processor/DSCv3/Unit/DSCv3ConfigurationUnitProcessor.cs b/src/Microsoft.Management.Configuration.Processor/DSCv3/Unit/DSCv3ConfigurationUnitProcessor.cs @@ -43,25 +43,25 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Unit /// <inheritdoc /> protected override ValueSet GetSettingsInternal() { - return this.processorSettings.DSCv3.GetResourceSettings(this.UnitInternal, this).Settings; + return this.processorSettings.DSCv3.GetResourceSettings(this.UnitInternal).Settings; } /// <inheritdoc /> protected override bool TestSettingsInternal() { - return this.processorSettings.DSCv3.TestResource(this.UnitInternal, this).InDesiredState; + return this.processorSettings.DSCv3.TestResource(this.UnitInternal).InDesiredState; } /// <inheritdoc /> protected override bool ApplySettingsInternal() { - return this.processorSettings.DSCv3.SetResourceSettings(this.UnitInternal, this).RebootRequired; + return this.processorSettings.DSCv3.SetResourceSettings(this.UnitInternal).RebootRequired; } /// <inheritdoc /> protected override IList<ValueSet>? GetAllSettingsInternal() { - var exportResult = this.processorSettings.DSCv3.ExportResource(this.UnitInternal, this); + var exportResult = this.processorSettings.DSCv3.ExportResource(this.UnitInternal); string expectedType = this.UnitInternal.QualifiedName.ToLowerInvariant(); List<ValueSet> result = new List<ValueSet>(); @@ -82,7 +82,7 @@ namespace Microsoft.Management.Configuration.Processor.DSCv3.Unit /// <inheritdoc /> protected override IList<ConfigurationUnit>? GetAllUnitsInternal() { - var exportResult = this.processorSettings.DSCv3.ExportResource(this.UnitInternal, this); + var exportResult = this.processorSettings.DSCv3.ExportResource(this.UnitInternal); List<ConfigurationUnit> result = new List<ConfigurationUnit>(); diff --git a/src/Microsoft.Management.Configuration.Processor/Factory/ConfigurationSetProcessorFactoryBase.cs b/src/Microsoft.Management.Configuration.Processor/Factory/ConfigurationSetProcessorFactoryBase.cs @@ -9,12 +9,13 @@ namespace Microsoft.Management.Configuration.Processor.Factory using System; using System.Runtime.CompilerServices; using Microsoft.Management.Configuration; + using Microsoft.Management.Configuration.Processor.DSCv3.Helpers; using Microsoft.Management.Configuration.Processor.Set; /// <summary> /// IConfigurationSetProcessorFactory base implementation. /// </summary> - internal abstract partial class ConfigurationSetProcessorFactoryBase + internal abstract partial class ConfigurationSetProcessorFactoryBase : IDiagnosticsSink { private bool isCreateProcessorInvoked = false; @@ -96,6 +97,12 @@ namespace Microsoft.Management.Configuration.Processor.Factory } } + /// <inheritdoc /> + void IDiagnosticsSink.OnDiagnostics(DiagnosticLevel level, string message) + { + this.OnDiagnostics(level, message); + } + /// <summary> /// Sends diagnostics if appropriate. /// </summary> diff --git a/src/Microsoft.Management.Configuration.Processor/Public/DSCv3ConfigurationSetProcessorFactory.cs b/src/Microsoft.Management.Configuration.Processor/Public/DSCv3ConfigurationSetProcessorFactory.cs @@ -31,6 +31,7 @@ namespace Microsoft.Management.Configuration.Processor /// </summary> public DSCv3ConfigurationSetProcessorFactory() { + this.processorSettings.DiagnosticsSink = this; } /// <summary> diff --git a/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestDSCv3.cs b/src/Microsoft.Management.Configuration.UnitTests/Helpers/TestDSCv3.cs @@ -102,31 +102,31 @@ namespace Microsoft.Management.Configuration.UnitTests.Helpers public ExportResourceDelegateType? ExportResourceDelegate { get; set; } /// <inheritdoc/> - public IResourceListItem? GetResourceByType(string resourceType, IDiagnosticsSink? diagnosticsSink = null) + public IResourceListItem? GetResourceByType(string resourceType) { return this.GetResourceByTypeResult ?? this.GetResourceByTypeDelegate?.Invoke(resourceType); } /// <inheritdoc/> - public IResourceGetItem GetResourceSettings(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IResourceGetItem GetResourceSettings(ConfigurationUnitInternal unitInternal) { return this.GetResourceSettingsResult ?? this.GetResourceSettingsDelegate?.Invoke(unitInternal) ?? throw new System.NotImplementedException(); } /// <inheritdoc/> - public IResourceSetItem SetResourceSettings(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IResourceSetItem SetResourceSettings(ConfigurationUnitInternal unitInternal) { return this.SetResourceSettingsResult ?? this.SetResourceSettingsDelegate?.Invoke(unitInternal) ?? throw new System.NotImplementedException(); } /// <inheritdoc/> - public IResourceTestItem TestResource(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IResourceTestItem TestResource(ConfigurationUnitInternal unitInternal) { return this.TestResourceResult ?? this.TestResourceDelegate?.Invoke(unitInternal) ?? throw new System.NotImplementedException(); } /// <inheritdoc/> - public IList<IResourceExportItem> ExportResource(ConfigurationUnitInternal unitInternal, IDiagnosticsSink? diagnosticsSink = null) + public IList<IResourceExportItem> ExportResource(ConfigurationUnitInternal unitInternal) { return this.ExportResourceResult ?? this.ExportResourceDelegate?.Invoke(unitInternal) ?? throw new System.NotImplementedException(); }