winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

ConfigurationUnitProcessorBase.cs (12718B)


      1 // -----------------------------------------------------------------------------
      2 // <copyright file="ConfigurationUnitProcessorBase.cs" company="Microsoft Corporation">
      3 //     Copyright (c) Microsoft Corporation. Licensed under the MIT License.
      4 // </copyright>
      5 // -----------------------------------------------------------------------------
      6 
      7 namespace Microsoft.Management.Configuration.Processor.Unit
      8 {
      9     using System;
     10     using System.Collections.Generic;
     11     using System.ComponentModel;
     12     using System.Runtime.CompilerServices;
     13     using Microsoft.Management.Configuration;
     14     using Microsoft.Management.Configuration.Processor.Exceptions;
     15     using Microsoft.Management.Configuration.Processor.Extensions;
     16     using Microsoft.Management.Configuration.Processor.Factory;
     17     using Microsoft.Management.Configuration.Processor.Helpers;
     18     using Windows.Foundation.Collections;
     19 
     20     /// <summary>
     21     /// IConfigurationUnitProcessor base implementation.
     22     /// </summary>
     23     internal abstract partial class ConfigurationUnitProcessorBase
     24     {
     25         private readonly ConfigurationUnitInternal unitInternal;
     26         private readonly bool isLimitMode;
     27 
     28         private bool isTestInvoked = false;
     29         private bool isApplyInvoked = false;
     30 
     31         /// <summary>
     32         /// Initializes a new instance of the <see cref="ConfigurationUnitProcessorBase"/> class.
     33         /// </summary>
     34         /// <param name="unitInternal">UnitInternal.</param>
     35         /// <param name="isLimitMode">Whether it is under limit mode.</param>
     36         internal ConfigurationUnitProcessorBase(ConfigurationUnitInternal unitInternal, bool isLimitMode)
     37         {
     38             this.unitInternal = unitInternal;
     39             this.isLimitMode = isLimitMode;
     40         }
     41 
     42         /// <summary>
     43         /// Gets the configuration unit that the processor was created for.
     44         /// </summary>
     45         public ConfigurationUnit Unit => this.unitInternal.Unit;
     46 
     47         /// <summary>
     48         /// Gets or initializes the set processor factory.
     49         /// </summary>
     50         internal ConfigurationSetProcessorFactoryBase? SetProcessorFactory { get; init; }
     51 
     52         /// <summary>
     53         /// Gets the internal configuration unit.
     54         /// </summary>
     55         protected ConfigurationUnitInternal UnitInternal => this.unitInternal;
     56 
     57         /// <summary>
     58         /// Gets the current system state for the configuration unit.
     59         /// Calls Get on the DSC resource.
     60         /// </summary>
     61         /// <returns>A <see cref="IGetSettingsResult"/>.</returns>
     62         public IGetSettingsResult GetSettings()
     63         {
     64             this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `Get` for resource: {this.unitInternal.QualifiedName}...");
     65 
     66             this.CheckLimitMode(ConfigurationUnitIntent.Inform);
     67             var result = new GetSettingsResult(this.Unit);
     68 
     69             try
     70             {
     71                 result.Settings = this.GetSettingsInternal();
     72             }
     73             catch (Exception e)
     74             {
     75                 this.ExtractExceptionInformation(e, result.InternalResult);
     76             }
     77 
     78             this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `Get`.");
     79             return result;
     80         }
     81 
     82         /// <summary>
     83         /// Determines if the system is already in the state described by the configuration unit.
     84         /// Calls Test on the DSC resource.
     85         /// </summary>
     86         /// <returns>A <see cref="ITestSettingsResult"/>.</returns>
     87         public ITestSettingsResult TestSettings()
     88         {
     89             this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `Test` for resource: {this.unitInternal.QualifiedName}...");
     90 
     91             if (this.Unit.Intent == ConfigurationUnitIntent.Inform)
     92             {
     93                 this.OnDiagnostics(DiagnosticLevel.Error, "`Test` should not be called on a unit with intent of `Inform`");
     94                 throw new NotSupportedException();
     95             }
     96 
     97             this.CheckLimitMode(ConfigurationUnitIntent.Assert);
     98             var result = new TestSettingsResult(this.Unit);
     99             result.TestResult = ConfigurationTestResult.Failed;
    100             try
    101             {
    102                 bool testResult = this.TestSettingsInternal();
    103 
    104                 result.TestResult = testResult ? ConfigurationTestResult.Positive : ConfigurationTestResult.Negative;
    105             }
    106             catch (Exception e)
    107             {
    108                 this.ExtractExceptionInformation(e, result.InternalResult);
    109             }
    110 
    111             this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `Test`.");
    112             return result;
    113         }
    114 
    115         /// <summary>
    116         /// Applies the state described in the configuration unit.
    117         /// Calls Set in the DSC resource.
    118         /// </summary>
    119         /// <returns>A <see cref="IApplySettingsResult"/>.</returns>
    120         public IApplySettingsResult ApplySettings()
    121         {
    122             this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `Apply` for resource: {this.unitInternal.QualifiedName}...");
    123 
    124             if (this.Unit.Intent == ConfigurationUnitIntent.Inform ||
    125                 this.Unit.Intent == ConfigurationUnitIntent.Assert)
    126             {
    127                 this.OnDiagnostics(DiagnosticLevel.Error, $"`Apply` should not be called on a unit with intent of `{this.Unit.Intent}`");
    128                 throw new NotSupportedException();
    129             }
    130 
    131             this.CheckLimitMode(ConfigurationUnitIntent.Apply);
    132             var result = new ApplySettingsResult(this.Unit);
    133             try
    134             {
    135                 result.RebootRequired = this.ApplySettingsInternal();
    136             }
    137             catch (Exception e)
    138             {
    139                 this.ExtractExceptionInformation(e, result.InternalResult);
    140             }
    141 
    142             this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `Apply`.");
    143             return result;
    144         }
    145 
    146         /// <summary>
    147         /// Gets the current settings for all the instances of a configuration unit.
    148         /// </summary>
    149         /// <returns>A <see cref="IGetAllSettingsResult"/>.</returns>
    150         public IGetAllSettingsResult GetAllSettings()
    151         {
    152             this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `GetAllSettings` for resource: {this.unitInternal.QualifiedName}...");
    153 
    154             this.CheckLimitMode(ConfigurationUnitIntent.Inform);
    155             var result = new GetAllSettingsResult(this.Unit);
    156 
    157             try
    158             {
    159                 result.Settings = this.GetAllSettingsInternal();
    160             }
    161             catch (Exception e)
    162             {
    163                 this.ExtractExceptionInformation(e, result.InternalResult);
    164             }
    165 
    166             this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `GetAllSettings`.");
    167             return result;
    168         }
    169 
    170         /// <summary>
    171         /// Gets all configuration units for the given unit type.
    172         /// Returned units may be of types other than the one passed in.
    173         /// </summary>
    174         /// <returns>A <see cref="IGetAllUnitsResult"/>.</returns>
    175         public IGetAllUnitsResult GetAllUnits()
    176         {
    177             this.OnDiagnostics(DiagnosticLevel.Verbose, $"Invoking `GetAllUnits` for resource: {this.unitInternal.QualifiedName}...");
    178 
    179             this.CheckLimitMode(ConfigurationUnitIntent.Inform);
    180             var result = new GetAllUnitsResult(this.Unit);
    181 
    182             try
    183             {
    184                 result.Units = this.GetAllUnitsInternal();
    185             }
    186             catch (Exception e)
    187             {
    188                 this.ExtractExceptionInformation(e, result.InternalResult);
    189             }
    190 
    191             this.OnDiagnostics(DiagnosticLevel.Verbose, $"... done invoking `GetAllUnits`.");
    192             return result;
    193         }
    194 
    195         /// <summary>
    196         /// Gets the current settings.
    197         /// </summary>
    198         /// <returns>The current settings.</returns>
    199         protected abstract ValueSet GetSettingsInternal();
    200 
    201         /// <summary>
    202         /// Tests the current settings.
    203         /// </summary>
    204         /// <returns>A boolean indicating whether the settings are in the desired state.</returns>
    205         protected abstract bool TestSettingsInternal();
    206 
    207         /// <summary>
    208         /// Applies the desired settings.
    209         /// </summary>
    210         /// <returns>A boolean indicating whether a reboot is required.</returns>
    211         protected abstract bool ApplySettingsInternal();
    212 
    213         /// <summary>
    214         /// Gets the current settings for all the instances of a configuration unit.
    215         /// Derive from IGetAllSettingsConfigurationUnitProcessor and implement an override to support this.
    216         /// </summary>
    217         /// <returns>The settings as ValueSets.</returns>
    218         protected virtual IList<ValueSet>? GetAllSettingsInternal()
    219         {
    220             throw new NotImplementedException("Configuration unit processor did not implement GetAllSettingsInternal.");
    221         }
    222 
    223         /// <summary>
    224         /// Gets all configuration units for the given unit type.
    225         /// Returned units may be of types other than the one passed in.
    226         /// Derive from IGetAllUnitsConfigurationUnitProcessor and implement an override to support this.
    227         /// </summary>
    228         /// <returns>The configuration units.</returns>
    229         protected virtual IList<ConfigurationUnit>? GetAllUnitsInternal()
    230         {
    231             throw new NotImplementedException("Configuration unit processor did not implement GetAllUnitsInternal.");
    232         }
    233 
    234         /// <summary>
    235         /// Sends diagnostics if appropriate.
    236         /// </summary>
    237         /// <param name="level">The level of this diagnostic message.</param>
    238         /// <param name="message">The diagnostic message.</param>
    239         protected void OnDiagnostics(DiagnosticLevel level, string message)
    240         {
    241             this.SetProcessorFactory?.OnDiagnostics(level, message);
    242         }
    243 
    244         private void ExtractExceptionInformation(Exception e, ConfigurationUnitResultInformation resultInformation)
    245         {
    246             this.OnDiagnostics(DiagnosticLevel.Verbose, e.ToString());
    247 
    248             IConfigurationUnitResultException? configurationUnitResultException = e as IConfigurationUnitResultException;
    249             if (configurationUnitResultException != null)
    250             {
    251                 resultInformation.ResultCode = e;
    252                 resultInformation.Description = configurationUnitResultException.Description;
    253                 resultInformation.Details = configurationUnitResultException.Details;
    254                 resultInformation.ResultSource = configurationUnitResultException.ResultSource;
    255             }
    256             else
    257             {
    258                 var inner = e.GetMostInnerException();
    259                 resultInformation.ResultCode = inner;
    260                 resultInformation.Description = e.Message;
    261                 resultInformation.Details = e.ToString();
    262                 resultInformation.ResultSource = ConfigurationUnitResultSource.Internal;
    263             }
    264         }
    265 
    266         [MethodImpl(MethodImplOptions.Synchronized)]
    267         private void CheckLimitMode(ConfigurationUnitIntent intent)
    268         {
    269             if (!this.isLimitMode)
    270             {
    271                 return;
    272             }
    273 
    274             if (intent == ConfigurationUnitIntent.Unknown)
    275             {
    276                 throw new InvalidEnumArgumentException(nameof(ConfigurationUnitIntent.Unknown));
    277             }
    278 
    279             if (intent == ConfigurationUnitIntent.Assert)
    280             {
    281                 if (this.isTestInvoked)
    282                 {
    283                     this.OnDiagnostics(DiagnosticLevel.Error, "TestSettings is already invoked in limit mode.");
    284                     throw new InvalidOperationException("TestSettings is already invoked in limit mode.");
    285                 }
    286                 else
    287                 {
    288                     this.isTestInvoked = true;
    289                 }
    290             }
    291 
    292             if (intent == ConfigurationUnitIntent.Apply)
    293             {
    294                 if (this.isApplyInvoked)
    295                 {
    296                     this.OnDiagnostics(DiagnosticLevel.Error, "ApplySettings is already invoked in limit mode.");
    297                     throw new InvalidOperationException("ApplySettings is already invoked in limit mode.");
    298                 }
    299                 else
    300                 {
    301                     this.isApplyInvoked = true;
    302                 }
    303             }
    304 
    305             // Get is always allowed now.
    306         }
    307     }
    308 }