ResourceDetails.cs (7575B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="ResourceDetails.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 7 namespace Microsoft.Management.Configuration.Processor.DSCv3.Helpers 8 { 9 using System; 10 using Microsoft.Management.Configuration.Processor.DSCv3.Model; 11 using Microsoft.Management.Configuration.Processor.Helpers; 12 using Microsoft.Management.Configuration.Processor.Unit; 13 14 /// <summary> 15 /// Cached data about a resource. 16 /// </summary> 17 internal class ResourceDetails 18 { 19 private readonly string resourceTypeName; 20 21 private object detailsUpdateLock = new object(); 22 private IResourceListItem? resourceListItem = null; 23 24 /// <summary> 25 /// The current level of detail stored by this object. 26 /// 27 /// The method of discovery for each of the levels in ConfigurationUnitDetailFlags: 28 /// None: No details, either because the resource was not found or EnsureDetails has not been called. 29 /// Local: `resource list` is used to determine the details. An embedded schema may enable "Load" details level. 30 /// Property information may not be available at this level. 31 /// Catalog: Same as local; there is currently no catalog to query against. 32 /// Download: Same as local; there is currently no catalog to find anything to download. 33 /// Load: `resource schema` is used to get the full schema for the resource. 34 /// This ensures that property information is available. 35 /// </summary> 36 private ConfigurationUnitDetailFlags currentDetailLevel = ConfigurationUnitDetailFlags.None; 37 38 /// <summary> 39 /// Initializes a new instance of the <see cref="ResourceDetails"/> class. 40 /// </summary> 41 /// <param name="resourceTypeName">The resource type name.</param> 42 public ResourceDetails(string resourceTypeName) 43 { 44 this.resourceTypeName = resourceTypeName; 45 } 46 47 /// <summary> 48 /// Gets a value indicating whether this resource exists. 49 /// Will be false until EnsureDetails is called and the resource is found. 50 /// </summary> 51 public bool Exists 52 { 53 get 54 { 55 lock (this.detailsUpdateLock) 56 { 57 return this.currentDetailLevel != ConfigurationUnitDetailFlags.None; 58 } 59 } 60 } 61 62 /// <summary> 63 /// Gets the path of the resource. 64 /// </summary> 65 public string? Path 66 { 67 get 68 { 69 lock (this.detailsUpdateLock) 70 { 71 return this.resourceListItem?.Path; 72 } 73 } 74 } 75 76 /// <summary> 77 /// Sets the resource list item directly to avoid duplicate "dsc resource list" calls. 78 /// </summary> 79 /// <param name="item">The resource list item.</param> 80 public void SetResourceListItem(IResourceListItem item) 81 { 82 lock (this.detailsUpdateLock) 83 { 84 if (this.resourceListItem != null) 85 { 86 throw new InvalidOperationException("Resource list item is already set"); 87 } 88 89 this.resourceListItem = item; 90 this.currentDetailLevel |= ConfigurationUnitDetailFlags.Local; 91 } 92 } 93 94 /// <summary> 95 /// Ensures that the given detail level is present. 96 /// </summary> 97 /// <param name="processorSettings">The processor settings to use when getting details.</param> 98 /// <param name="detailFlags">The detail level flags.</param> 99 public void EnsureDetails(ProcessorSettings processorSettings, ConfigurationUnitDetailFlags detailFlags) 100 { 101 if (this.DetailsNeededFor(detailFlags, ConfigurationUnitDetailFlags.Local)) 102 { 103 // If we can't get local details, then exit until we have more options. 104 if (!this.GetLocalDetails(processorSettings)) 105 { 106 return; 107 } 108 } 109 110 if (this.DetailsNeededFor(detailFlags, ConfigurationUnitDetailFlags.Load)) 111 { 112 this.GetLoadDetails(processorSettings); 113 } 114 } 115 116 /// <summary> 117 /// Gets a ConfigurationUnitProcessorDetails populated with all available data. 118 /// </summary> 119 /// <returns>A ConfigurationUnitProcessorDetails populated with all available data.</returns> 120 public ConfigurationUnitProcessorDetails? GetConfigurationUnitProcessorDetails() 121 { 122 if (!this.Exists) 123 { 124 return null; 125 } 126 127 ConfigurationUnitProcessorDetails result = new ConfigurationUnitProcessorDetails() { UnitType = this.resourceTypeName }; 128 129 lock (this.detailsUpdateLock) 130 { 131 if (this.resourceListItem != null) 132 { 133 result.UnitType = this.resourceListItem.Type; 134 result.IsGroup = IsGroup(this.resourceListItem.Kind); 135 result.Version = this.resourceListItem.Version; 136 result.UnitDescription = this.resourceListItem.Description; 137 result.Author = this.resourceListItem.Author; 138 result.Path = this.resourceListItem.Path; 139 140 result.IsLocal = true; 141 } 142 } 143 144 return result; 145 } 146 147 private static bool IsGroup(ResourceKind kind) => kind switch 148 { 149 ResourceKind.Adapter => true, 150 ResourceKind.Group => true, 151 _ => false, 152 }; 153 154 private bool DetailsNeededFor(ConfigurationUnitDetailFlags detailFlags, ConfigurationUnitDetailFlags targetLevel) 155 { 156 if (!detailFlags.HasFlag(targetLevel)) 157 { 158 return false; 159 } 160 161 lock (this.detailsUpdateLock) 162 { 163 return !this.currentDetailLevel.HasFlag(targetLevel); 164 } 165 } 166 167 private bool GetLocalDetails(ProcessorSettings processorSettings) 168 { 169 IResourceListItem? resourceListItem = processorSettings.DSCv3.GetResourceByType(this.resourceTypeName, null); 170 171 if (resourceListItem != null) 172 { 173 // TODO: Attempt to extract embedded schema to avoid the need for Load. 174 lock (this.detailsUpdateLock) 175 { 176 if (!this.currentDetailLevel.HasFlag(ConfigurationUnitDetailFlags.Local)) 177 { 178 this.resourceListItem = resourceListItem; 179 this.currentDetailLevel |= ConfigurationUnitDetailFlags.Local; 180 } 181 } 182 183 return true; 184 } 185 else 186 { 187 return false; 188 } 189 } 190 191 private void GetLoadDetails(ProcessorSettings processorSettings) 192 { 193 throw new NotImplementedException(); 194 } 195 } 196 }