FindDscPackageStateMachine.cs (7334B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="FindDscPackageStateMachine.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 11 /// <summary> 12 /// Provides the state machine that decides which DSC package to use. 13 /// </summary> 14 internal class FindDscPackageStateMachine 15 { 16 private const string StableDscPackageFamilyName = "Microsoft.DesiredStateConfiguration_8wekyb3d8bbwe"; 17 private const string PreviewDscPackageFamilyName = "Microsoft.DesiredStateConfiguration-Preview_8wekyb3d8bbwe"; 18 19 private readonly Version minimumStableVersion = new Version(3, 1); 20 private readonly Version minimumPreviewVersion = new Version(3, 1, 7); 21 22 private State currentState = State.Initial; 23 private string? dscExecutablePath; 24 25 /// <summary> 26 /// A state of the state machine. 27 /// </summary> 28 public enum State 29 { 30 /// <summary> 31 /// The initial state. 32 /// </summary> 33 Initial, 34 35 /// <summary> 36 /// A stable installation attempt has been made. 37 /// </summary> 38 StableInstallAttempted, 39 40 /// <summary> 41 /// A preview installation attempt has been made. 42 /// </summary> 43 PreviewInstallAttempted, 44 45 /// <summary> 46 /// The state machine is terminated. 47 /// </summary> 48 Terminated, 49 } 50 51 /// <summary> 52 /// A transition of the state machine. 53 /// </summary> 54 public enum Transition 55 { 56 /// <summary> 57 /// Transition to a terminated state with DSC being found. 58 /// </summary> 59 Found, 60 61 /// <summary> 62 /// Attempt to install the stable version of DSC. 63 /// </summary> 64 InstallStable, 65 66 /// <summary> 67 /// Attempt to install the preview version of DSC. 68 /// </summary> 69 InstallPreview, 70 71 /// <summary> 72 /// Transition to a terminated state with DSC *not* being found. 73 /// </summary> 74 NotFound, 75 } 76 77 /// <summary> 78 /// Gets the file path of the DSC (Desired State Configuration) executable. 79 /// </summary> 80 public string? DscExecutablePath 81 { 82 get 83 { 84 if (this.currentState == State.Terminated) 85 { 86 return this.dscExecutablePath; 87 } 88 else 89 { 90 PackageInformation stableInformation = new PackageInformation(StableDscPackageFamilyName); 91 if (stableInformation.IsInstalled && stableInformation.Version >= this.minimumStableVersion) 92 { 93 return stableInformation.AliasPath; 94 } 95 else 96 { 97 PackageInformation previewInformation = new PackageInformation(PreviewDscPackageFamilyName); 98 if (previewInformation.IsInstalled && previewInformation.Version >= this.minimumPreviewVersion) 99 { 100 return previewInformation.AliasPath; 101 } 102 else 103 { 104 return null; 105 } 106 } 107 } 108 } 109 } 110 111 /// <summary> 112 /// Determines the next state transition based on the current context or conditions. 113 /// </summary> 114 /// <returns> 115 /// A string representing the name of the next transition. 116 /// </returns> 117 public Transition DetermineNextTransition() 118 { 119 switch (this.currentState) 120 { 121 case State.Initial: 122 { 123 PackageInformation stableInformation = new PackageInformation(StableDscPackageFamilyName); 124 if (stableInformation.IsInstalled && stableInformation.Version >= this.minimumStableVersion) 125 { 126 return this.Found(stableInformation); 127 } 128 else 129 { 130 this.currentState = State.StableInstallAttempted; 131 return Transition.InstallStable; 132 } 133 } 134 135 case State.StableInstallAttempted: 136 { 137 PackageInformation stableInformation = new PackageInformation(StableDscPackageFamilyName); 138 if (stableInformation.IsInstalled && stableInformation.Version >= this.minimumStableVersion) 139 { 140 return this.Found(stableInformation); 141 } 142 else 143 { 144 PackageInformation previewInformation = new PackageInformation(PreviewDscPackageFamilyName); 145 if (previewInformation.IsInstalled && previewInformation.Version >= this.minimumPreviewVersion) 146 { 147 return this.Found(previewInformation); 148 } 149 else 150 { 151 this.currentState = State.PreviewInstallAttempted; 152 return Transition.InstallPreview; 153 } 154 } 155 } 156 157 case State.PreviewInstallAttempted: 158 { 159 PackageInformation previewInformation = new PackageInformation(PreviewDscPackageFamilyName); 160 if (previewInformation.IsInstalled && previewInformation.Version >= this.minimumPreviewVersion) 161 { 162 return this.Found(previewInformation); 163 } 164 else 165 { 166 this.currentState = State.Terminated; 167 return Transition.NotFound; 168 } 169 } 170 171 case State.Terminated: 172 return this.DscExecutablePath == null ? Transition.NotFound : Transition.Found; 173 174 default: 175 throw new InvalidOperationException($"Unexpected state: {this.currentState}"); 176 } 177 } 178 179 private Transition Found(PackageInformation packageInformation) 180 { 181 this.dscExecutablePath = packageInformation.AliasPath; 182 this.currentState = State.Terminated; 183 return Transition.Found; 184 } 185 } 186 }