// Clean install requires machine be free of previous Fabric installations private static bool CheckForCleanInstall(StandAloneInstallerJsonModelBase config, MachineHealthContainer machineHealthContainer, bool isForcedRun = false) { SFDeployerTrace.WriteNoise(StringResources.Info_BPANoFabric); List <string> machineNamesTemp = StandaloneUtility.GetMachineNamesIncludingClient(machineHealthContainer.GetHealthyMachineNames()); var importantSettings = config.GetFabricSystemSettings(); string fabricDataRoot = importantSettings.ContainsKey(DMConstants.FabricDataRootString) ? importantSettings[DMConstants.FabricDataRootString] : null; bool localMachineFailed = false; Parallel.ForEach( machineNamesTemp, (string machineName) => { bool result = true; if (StandaloneUtility.IsFabricInstalled(machineName)) { SFDeployerTrace.WriteError(StringResources.Error_BPAPreviousFabricExists, machineName); result = false; } if (!isForcedRun) { if (fabricDataRoot != null) { IEnumerable <string> machineNodes = config.Nodes.Where(n => n.IPAddress == machineName).Select(n => n.NodeName); foreach (string node in machineNodes) { string nodeDirectory; if (StandaloneUtility.DataRootNodeExists(machineName, node, fabricDataRoot, out nodeDirectory)) { SFDeployerTrace.WriteError(StringResources.Error_BPADataRootNodeExists, node, machineName, nodeDirectory); result = false; } } } } if (!result) { if (Helpers.IsLocalIpAddress(machineName)) { localMachineFailed = true; } else { machineHealthContainer.MarkMachineAsUnhealthy(machineName); } } }); if (localMachineFailed) { return(false); } return(machineHealthContainer.EnoughHealthyMachines()); }
internal static bool IsJsonConfigModelValid(StandAloneInstallerJsonModelBase config, StandAloneInstallerJsonModelBase oldConfig, bool validateDownNodes, bool throwIfError = false) { try { config.ThrowValidationExceptionIfNull(StringResources.Error_BPAJsonModelInvalid); config.ValidateModel(); var settingsValidator = new StandaloneSettingsValidator(config); settingsValidator.Validate(validateDownNodes); // UOS validates upgrade config diffs by calling ValidateUpdateFrom() method directly. Test-Configuration invokes IsJsonConfigModelValid() and it calls ValidateUpdateFrom inside. // The reason is from Test-Configuration, there is no cluster connection, so that we ignore ValidateTopologyAsync(). Therefore in the ValidateUpdateFrom here there is no need // to await the async call. However in UOS, we should call ValidateUpdateFrom in an async manner. That's why I am not trying to have the UOS/TestConfiguration going down the same path. if (oldConfig != null) { settingsValidator.ValidateUpdateFrom(oldConfig.GetUserConfig(), oldConfig.GetClusterTopology(), connectedToCluster: false).GetAwaiter().GetResult(); } } catch (FileNotFoundException ex) { SFDeployerTrace.WriteError(StringResources.Error_BPAPackageFileNotFound, ex.ToString()); return(false); } catch (ValidationException ex) { SFDeployerTrace.WriteError(StringResources.Error_BPAModelSettingsValidationFailed, ex.GetMessage(System.Globalization.CultureInfo.InvariantCulture)); if (throwIfError) { throw; } return(false); } return(true); }
internal static void UpdateStandAloneClusterForRemoveNode(string targetJsonFilePath, StandAloneCluster existingCluster) { StandAloneInstallerJsonModelBase targetJsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(Path.Combine(Utility.TestDirectory, targetJsonFilePath)); StandaloneSettingsValidator validator = new StandaloneSettingsValidator(targetJsonConfig); existingCluster.TargetCsmConfig = validator.ClusterProperties; existingCluster.Topology = validator.Topology; List <NodeStatus> nodeStatus = new List <NodeStatus>(); foreach (var node in existingCluster.Current.NodeConfig.NodesStatus) { NodeStatus ns = new NodeStatus(); ns.NodeName = node.NodeName; ns.NodeState = targetJsonConfig.Nodes.Select(n => n.NodeName).Contains(node.NodeName) ? NodeState.Enabled : NodeState.Removed; ns.NodeDeactivationIntent = targetJsonConfig.Nodes.Select(n => n.NodeName).Contains(node.NodeName) ? WrpNodeDeactivationIntent.Invalid : WrpNodeDeactivationIntent.RemoveNode; ns.NodeType = node.NodeType; ns.InstanceId = 0; nodeStatus.Add(ns); } existingCluster.TargetNodeConfig = new ClusterNodeConfig { NodesStatus = nodeStatus, Version = 3 }; }
public void ConstructorTest() { StandAloneInstallerJsonModelBase jsonConfig; jsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(Path.Combine(Utility.TestDirectory, TestFiles.GAv1)); Assert.IsInstanceOfType(jsonConfig, typeof(StandAloneInstallerJsonModelGA)); jsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(Path.Combine(Utility.TestDirectory, TestFiles.Jan2017v1)); Assert.IsInstanceOfType(jsonConfig, typeof(StandAloneInstallerJSONModelJan2017)); this.AddonConstructorTest(TestFiles.April2017HasAddon, new AddonFeature[] { AddonFeature.RepairManager, AddonFeature.DnsService }, typeof(StandAloneInstallerJSONModelApril2017)); this.AddonConstructorTest(TestFiles.April2017NoAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelApril2017)); this.AddonConstructorTest(TestFiles.April2017HasUnsupportedAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelApril2017), expectError: true); this.AddonConstructorTest(TestFiles.May2017HasAddon, new AddonFeature[] { AddonFeature.RepairManager, AddonFeature.DnsService }, typeof(StandAloneInstallerJSONModelMay2017)); this.AddonConstructorTest(TestFiles.May2017NoAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelMay2017)); this.AddonConstructorTest(TestFiles.May2017HasUnsupportedAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelMay2017), expectError: true); this.AddonConstructorTest(TestFiles.Aug2017HasAddon, new AddonFeature[] { AddonFeature.RepairManager, AddonFeature.DnsService, AddonFeature.BackupRestoreService }, typeof(StandAloneInstallerJSONModelAugust2017)); this.AddonConstructorTest(TestFiles.Aug2017NoAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelAugust2017)); this.AddonConstructorTest(TestFiles.Aug2017HasUnsupportedAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelAugust2017), expectError: true); this.AddonConstructorTest(TestFiles.Oct2017HasAddon, new AddonFeature[] { AddonFeature.RepairManager, AddonFeature.DnsService, AddonFeature.BackupRestoreService }, typeof(StandAloneInstallerJSONModelOctober2017)); this.AddonConstructorTest(TestFiles.Oct2017NoAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelOctober2017)); this.AddonConstructorTest(TestFiles.Oct2017HasUnsupportedAddon, new AddonFeature[0], typeof(StandAloneInstallerJSONModelOctober2017), expectError: true); }
public async Task <string> ProcessGetClusterConfigurationAsync(string apiVersion, TimeSpan timeout, CancellationToken cancellationToken) { UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Entering ProcessGetClusterConfigurationAsync."); try { UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Retrieve current cluster resource from StoreManager."); StandAloneCluster cluster = await this.storeManager.GetClusterResourceAsync( Constants.ClusterReliableDictionaryKey, this.cancellationToken).ConfigureAwait(false); if (cluster == null || cluster.Current == null) { // read from fabric data root string fabricDataRoot = FabricEnvironment.GetDataRoot(); string jsonConfigPath = Path.Combine(fabricDataRoot, System.Fabric.FabricDeployer.Constants.FileNames.BaselineJsonClusterConfig); // TODO: Needs to come from image store return(File.ReadAllText(jsonConfigPath)); } else { var nodesFromFM = new Dictionary <string, NodeDescription>(); NodeList nodes = await StandaloneUtility.GetNodesFromFMAsync(this.fabricClient, this.cancellationToken).ConfigureAwait(false); for (int i = 0; i < nodes.Count; ++i) { if (nodes[i].NodeStatus != System.Fabric.Query.NodeStatus.Invalid && !UpgradeOrchestrationMessageProcessor.IsGhostNode(nodes[i])) { NodeDescription nodeDesc = new NodeDescription() { FaultDomain = nodes[i].FaultDomain.ToString(), UpgradeDomain = nodes[i].UpgradeDomain, IPAddress = nodes[i].IpAddressOrFQDN, NodeTypeRef = nodes[i].NodeType, NodeName = nodes[i].NodeName }; nodesFromFM.Add(nodes[i].NodeName, nodeDesc); } } cluster.Topology.Nodes = nodesFromFM; UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Construct StandAloneJsonModel from current cluster resource."); var jsonModel = StandAloneInstallerJsonModelBase.ConstructByApiVersion(cluster.Current.CSMConfig, cluster.Topology, cluster.Current.CSMConfig.Version.Version, apiVersion); UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Serializing current json model."); var serializerSettings = new JsonSerializerSettings { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, PreserveReferencesHandling = PreserveReferencesHandling.None }; serializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); return(JsonConvert.SerializeObject(jsonModel, serializerSettings)); } } catch (Exception e) { UpgradeOrchestrationTrace.TraceSource.WriteWarning(TraceType, "ProcessStartUpgradeAsync exception: {0}", e); throw UpgradeOrchestrationMessageProcessor.ConvertToComException(e); } }
internal static async Task ValidateModel(StandAloneInstallerJsonModelBase targetJsonConfig, StandaloneSettingsValidator validator, StandAloneCluster cluster, bool validateUpgrade) { BestPracticesAnalyzer.IsJsonConfigModelValid(targetJsonConfig, oldConfig: null, validateDownNodes: false, throwIfError: true); if (validateUpgrade) { await validator.ValidateUpdateFrom(cluster.Current.CSMConfig, cluster.Topology, connectedToCluster : true).ConfigureAwait(false); } }
public void DeploymentManagerTest_DefaultUosConfigValuesMultibox() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigMultiboxFilename); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); var userConfig = configModel.GetUserConfig(); Assert.IsTrue(userConfig.AutoupgradeEnabled == true, "Multibox AutoupgradeEnabled should be defaulted to false."); }
public void DeploymentManagerTest_ValidateJsonConfigCodeUpgradeJune2018() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigCodeUpgradeJune2018Filename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); Assert.IsNotNull(configModel, "JSON config was invalid."); var userConfig = configModel.GetUserConfig(); Assert.IsTrue(userConfig.CodeVersion == "5.5.0.0", "Code version should be 5.5.0.0."); }
protected void NewCluster(string clusterConfigurationFilePath, string fabricPackageSourcePath, bool noCleanupOnFailure, bool force, int maxPercentFailedNodes, uint timeoutInSeconds) { this.ChangeCurrentDirectoryToSession(); clusterConfigurationFilePath = this.GetAbsolutePath(clusterConfigurationFilePath); fabricPackageSourcePath = this.GetAbsolutePath(fabricPackageSourcePath); ClusterCreationOptions creationOptions = ClusterCreationOptions.None; if (noCleanupOnFailure) { creationOptions |= ClusterCreationOptions.OptOutCleanupOnFailure; } if (force) { creationOptions |= ClusterCreationOptions.Force; } TimeSpan?timeout = null; if (timeoutInSeconds > 0) { timeout = TimeSpan.FromSeconds(timeoutInSeconds); } try { this.WriteObject(StringResources.Info_CreatingServiceFabricCluster); this.WriteObject(StringResources.Info_CreatingServiceFabricClusterDebugDetails); DeploymentManager.CreateClusterAsync( clusterConfigurationFilePath, fabricPackageSourcePath, creationOptions, maxPercentFailedNodes, timeout).Wait(); var standAloneModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigurationFilePath); var node = standAloneModel.Nodes[0]; var nodeType = standAloneModel.GetUserConfig().NodeTypes.Find(type => type.Name == node.NodeTypeRef); this.WriteObject(string.Format(StringResources.Info_CreateServiceFabricClusterSucceeded, node.IPAddress, nodeType.ClientConnectionEndpointPort)); } catch (Exception exception) { this.WriteObject(StringResources.Error_CreateServiceFabricClusterFailed); this.WriteObject(exception.InnerException != null ? exception.InnerException.Message : exception.Message); this.ThrowTerminatingError( exception, Constants.NewNodeConfigurationErrorId, null); } }
internal static void UpdateStandAloneCluster(string targetJsonFilePath, StandAloneCluster existingCluster, bool isUserSet = false) { StandAloneInstallerJsonModelBase targetJsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(Path.Combine(Utility.TestDirectory, targetJsonFilePath)); StandaloneSettingsValidator validator = new StandaloneSettingsValidator(targetJsonConfig); existingCluster.TargetCsmConfig = validator.ClusterProperties; existingCluster.Topology = validator.Topology; if (!string.IsNullOrEmpty(validator.ClusterProperties.CodeVersion)) { var adminConfigVersion = new StandaloneAdminConfig(null, isUserSet); adminConfigVersion.Version.MsiVersion = validator.ClusterProperties.CodeVersion; existingCluster.TargetWrpConfig = adminConfigVersion; } }
internal static StandAloneCluster ConstructClusterFromJson(StandAloneInstallerJsonModelBase jsonModel, FabricNativeConfigStore configStore) { UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Creating userconfig, cluster topology, adminconfig."); var userConfig = jsonModel.GetUserConfig(); var clusterTopology = jsonModel.GetClusterTopology(); var adminConfig = new StandaloneAdminConfig(); var logger = new StandAloneTraceLogger("StandAloneDeploymentManager"); UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Creating new StandAlone cluster resource."); var clusterId = configStore.ReadUnencryptedString(Constants.SectionName, Constants.ClusterIdParameterName); var clusterResource = new StandAloneCluster(adminConfig, userConfig, clusterTopology, clusterId, logger); return(clusterResource); }
public void DeploymentManagerTest_ValidateIncorrectJsonConfig() { string jsonFilePath = Path.Combine(BaseDir, XmlManifestFilename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(jsonFilePath); Assert.IsTrue(File.Exists(jsonFilePath), string.Format("Manifest file {0} did not exist.", jsonFilePath)); Assert.IsNull(configModel, "Cluster manifest should not have been valid JSON."); foreach (string fileName in unsupportedApiVersionJsonConfigFileNames) { jsonFilePath = Path.Combine(BaseDir, fileName); Assert.IsTrue(File.Exists(jsonFilePath)); configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(jsonFilePath); Assert.IsNull(configModel); } }
private static bool ValidateCodeVersionExists(StandAloneInstallerJsonModelBase config) { var userConfig = config.GetUserConfig(); if (!string.IsNullOrEmpty(userConfig.CodeVersion)) { Version ver; if (userConfig.CodeVersion != DMConstants.AutoupgradeCodeVersion && !Version.TryParse(userConfig.CodeVersion, out ver)) { SFDeployerTrace.WriteError(StringResources.Error_SFCodeVersionUnsupportedForDeployment); return(false); } } return(true); }
public void DeploymentManagerTest_InvalidJsonConfigWindowsGMSAOct2017() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigWindowsGMSAInvalidOct2017Filename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); Assert.IsNotNull(configModel, "JSON config was invalid."); var settingsValidator = new StandaloneSettingsValidator(configModel); Utility.ValidateExpectedValidationException( delegate { settingsValidator.Validate(false); }, ClusterManagementErrorCode.BestPracticesAnalyzerModelInvalid); }
internal static StandAloneCluster PopulateStandAloneClusterWithBaselineJson(string jsonFilePath) { StandAloneInstallerJsonModelBase jsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(Path.Combine(Utility.TestDirectory, jsonFilePath)); var userConfig = jsonConfig.GetUserConfig(); var clusterTopology = jsonConfig.GetClusterTopology(); var adminConfig = new StandaloneAdminConfig(); var logger = new StandAloneTraceLogger("StandAloneDeploymentManager"); string customizedClusterId = jsonConfig.GetClusterRegistrationId(); return(new StandAloneCluster( adminConfig, userConfig, clusterTopology, customizedClusterId ?? "acf4dc93-9b64-4504-8b6f-0b7fd052e096", logger)); }
private async Task <string> GetCurrentJsonConfigVersionAsync(CancellationToken cancellationToken) { StandAloneCluster cluster = await this.storeManager.GetClusterResourceAsync( Constants.ClusterReliableDictionaryKey, this.cancellationToken).ConfigureAwait(false); if (cluster == null || cluster.Current == null) { // read from fabric data root string fabricDataRoot = FabricEnvironment.GetDataRoot(); string jsonConfigPath = Path.Combine(fabricDataRoot, System.Fabric.FabricDeployer.Constants.FileNames.BaselineJsonClusterConfig); // TODO: Needs to come from image store string jsonConfigString = File.ReadAllText(jsonConfigPath); StandAloneInstallerJsonModelBase targetJsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromString(jsonConfigString); return(targetJsonConfig.ClusterConfigurationVersion); } else { return(cluster.Current.CSMConfig.Version.Version); } }
public void DeploymentManagerTest_ValidateJsonConfigUnsecureJan2017() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigUnsecureJan2017Filename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); Assert.IsNotNull(configModel, "JSON config was invalid."); var userConfig = configModel.GetUserConfig(); Assert.IsNull(userConfig.Security, "Security must be null."); var clusterTopology = configModel.GetClusterTopology(); Assert.IsNotNull(clusterTopology.Nodes); Assert.IsNotNull(clusterTopology.Machines); Assert.IsTrue(clusterTopology.Nodes.Count > 0, "Cluster JSON config was not written correctly. Nodes missing."); Assert.IsTrue(clusterTopology.Machines.Count > 0, "Cluster JSON config was not written correctly. Machines missing."); }
internal static bool ValidateClusterRemoval( string configPath, bool usingClusterManifest = false) { SFDeployerTrace.WriteInfo(StringResources.Info_BPAStart); var summary = new AnalysisSummary(); // Check user has local admin privilege summary.LocalAdminPrivilege = CheckLocalAdminPrivilege(); StandAloneInstallerJsonModelBase standAloneModel = null; if (!usingClusterManifest) { standAloneModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(configPath); summary.IsJsonValid = IsJsonConfigModelValid(standAloneModel, null, validateDownNodes: false, throwIfError: false); } // Below depends on JSON being valid if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(false); } // Get machine names from JSON config IEnumerable <string> machineNames = usingClusterManifest ? StandaloneUtility.GetMachineNamesFromClusterManifest(configPath) : standAloneModel.GetClusterTopology().Machines; MachineHealthContainer machineHealthContainer = new MachineHealthContainer(machineNames); // Log validations but don't fail StandaloneUtility.CheckRequiredPorts(machineHealthContainer); CheckRPCAccess(machineHealthContainer); // At least one machine should be removable bool anyMachinesRemovable = CheckAnyMachinesRemovable(machineNames); LogResult(summary, anyMachinesRemovable); return(summary.Passed); }
public void DeploymentManagerTest_ValidateJsonConfigWindowsSecureGA() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigWindowsSecureGAFilename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); Assert.IsNotNull(configModel, "JSON config was invalid."); var userConfig = configModel.GetUserConfig(); Assert.IsNotNull(userConfig.Security.WindowsIdentities, "Windows Identities should be provided."); Assert.IsNotNull(userConfig.Security.ClusterCredentialType == Microsoft.ServiceFabric.ClusterManagementCommon.CredentialType.Windows, "ClusterCredentialType must be Windows."); var clusterTopology = configModel.GetClusterTopology(); Assert.IsNotNull(clusterTopology.Nodes); Assert.IsNotNull(clusterTopology.Machines); Assert.IsTrue(clusterTopology.Nodes.Count > 0, "Cluster JSON config was not written correctly. Nodes missing."); Assert.IsTrue(clusterTopology.Machines.Count > 0, "Cluster JSON config was not written correctly. Machines missing."); }
public void DeploymentManagerTest_ValidateJsonConfigX509SecureJan2017() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigX509SecureJan2017Filename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); Assert.IsNotNull(configModel, "JSON config was invalid."); var userConfig = configModel.GetUserConfig(); Assert.IsNotNull(userConfig.Security.CertificateInformation, "X509 Certificate information must not be null"); Assert.IsNotNull(userConfig.Security.ClusterCredentialType == Microsoft.ServiceFabric.ClusterManagementCommon.CredentialType.X509, "ClusterCredentialType must be X509."); var clusterTopology = configModel.GetClusterTopology(); Assert.IsNotNull(clusterTopology.Nodes); Assert.IsNotNull(clusterTopology.Machines); Assert.IsTrue(clusterTopology.Nodes.Count > 0, "Cluster JSON config was not written correctly. Nodes missing."); Assert.IsTrue(clusterTopology.Machines.Count > 0, "Cluster JSON config was not written correctly. Machines missing."); }
public void DeploymentManagerTest_ValidateJsonConfigNodeTypePortCollision() { string jsonFilePath = Path.Combine(BaseDir, JsonConfigUnsecureGAFilename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(jsonFilePath); Assert.IsTrue(File.Exists(jsonFilePath), string.Format("Config file {0} did not exist.", jsonFilePath)); configModel.ValidateModel(); foreach (string fileName in portCollissionJsonConfigFileNames) { jsonFilePath = Path.Combine(BaseDir, fileName); Assert.IsTrue(File.Exists(jsonFilePath), string.Format("Config file {0} did not exist.", jsonFilePath)); configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(jsonFilePath); Utility.ValidateExpectedValidationException( delegate { configModel.ValidateModel(); }, ClusterManagementErrorCode.BestPracticesAnalyzerModelInvalid); } }
public void DeploymentManagerTest_ValidateJsonConfigIssuerCertStoreOctober2017() { string clusterConfigPath = Path.Combine(BaseDir, JsonConfigX509SecureIssuerCNOct2017Filename); var configModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(clusterConfigPath); Assert.IsTrue(File.Exists(clusterConfigPath), string.Format("Config file {0} did not exist.", clusterConfigPath)); Assert.IsNotNull(configModel, "JSON config was invalid."); var userConfig = configModel.GetUserConfig(); Assert.IsTrue(userConfig.Security.CertificateInformation.ClusterCertificateIssuerStores.Count() == 2, "ClusterCertificateIssuerStore count should be 2."); Assert.IsTrue(userConfig.Security.CertificateInformation.ServerCertificateIssuerStores.Count() == 1, "ServerCertificateIssuerStore count should be 1."); Assert.IsTrue(userConfig.Security.CertificateInformation.ClientCertificateIssuerStores.Count() == 1, "ClientCertificateIssuerStore count should be 1."); var clusterResource = DeploymentManagerInternal.GetClusterResource(clusterConfigPath, System.Guid.NewGuid().ToString()); var cm = clusterResource.Current.ExternalState.ClusterManifest; var clusterCertificateIssuerStore = cm.FabricSettings.ToList().Where(section => section.Name == StringConstants.SectionName.SecurityClusterCertificateIssuerStores).ToList(); Assert.IsTrue(clusterCertificateIssuerStore.Count() == 1, "clusterCertificateIssuerStore count should be 1"); Assert.IsTrue(clusterCertificateIssuerStore[0].Parameter.ToList().Count == 2, "clusterCertificateIssuerStore parameter count should be 2"); Assert.AreEqual(clusterCertificateIssuerStore[0].Parameter[0].Name, ""); Assert.AreEqual(clusterCertificateIssuerStore[0].Parameter[0].Value, "My"); Assert.AreEqual(clusterCertificateIssuerStore[0].Parameter[1].Name, "ClusterIssuer"); Assert.AreEqual(clusterCertificateIssuerStore[0].Parameter[1].Value, "My, Root"); var serverCertificateIssuerStore = cm.FabricSettings.ToList().Where(section => section.Name == StringConstants.SectionName.SecurityServerCertificateIssuerStores).ToList(); Assert.IsTrue(serverCertificateIssuerStore.Count() == 1, "serverCertificateIssuerStore count should be 1"); Assert.IsTrue(serverCertificateIssuerStore[0].Parameter.ToList().Count == 1, "serverCertificateIssuerStore parameter count should be 1"); Assert.AreEqual(serverCertificateIssuerStore[0].Parameter[0].Name, "ServerIssuer"); Assert.AreEqual(serverCertificateIssuerStore[0].Parameter[0].Value, "My"); var clientCertificateIssuerStore = cm.FabricSettings.ToList().Where(section => section.Name == StringConstants.SectionName.SecurityClientCertificateIssuerStores).ToList(); Assert.IsTrue(clientCertificateIssuerStore.Count() == 1, "clientCertificateIssuerStore count should be 1"); Assert.IsTrue(clientCertificateIssuerStore[0].Parameter.ToList().Count == 1, "clientCertificateIssuerStore parameter count should be 1"); Assert.AreEqual(clientCertificateIssuerStore[0].Parameter[0].Name, "ClientIssuer"); Assert.AreEqual(clientCertificateIssuerStore[0].Parameter[0].Value, "My"); }
private void AddonConstructorTest(string jsonFile, AddonFeature[] expectedAddonFeatures, Type modelType, bool expectError = false) { StandAloneInstallerJsonModelBase jsonConfig; try { jsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(Path.Combine(Utility.TestDirectory, jsonFile)); if (expectError) { if (jsonConfig != null) { throw new Exception("test failure"); } else { return; } } } catch (Exception ex) { if (!expectError) { throw new Exception("test failure", ex); } return; } bool isAprilModel = jsonConfig.GetType() == typeof(StandAloneInstallerJSONModelApril2017); bool isMayModel = jsonConfig.GetType() == typeof(StandAloneInstallerJSONModelMay2017); bool isAugModel = jsonConfig.GetType() == typeof(StandAloneInstallerJSONModelAugust2017); bool isOctModel = jsonConfig.GetType() == typeof(StandAloneInstallerJSONModelOctober2017); PropertyApril2017 aprilProperty = null; PropertyMay2017 mayProperty = null; PropertyAugust2017 augProperty = null; PropertyOctober2017 octProperty = null; // deserialization test Assert.IsInstanceOfType(jsonConfig, modelType); if (isAprilModel) { aprilProperty = (PropertyApril2017)((StandAloneInstallerJSONModelApril2017)jsonConfig).Properties; Assert.AreEqual(expectedAddonFeatures.Length, aprilProperty.AddonFeatures.Count); Assert.IsTrue(aprilProperty.AddonFeatures.All(p => expectedAddonFeatures.Contains(p))); Assert.IsTrue(expectedAddonFeatures.All(p => aprilProperty.AddonFeatures.Contains(p))); Assert.IsNull(aprilProperty.TestHookReliabilityLevel); } else if (isMayModel) { mayProperty = (PropertyMay2017)((StandAloneInstallerJSONModelMay2017)jsonConfig).Properties; Assert.AreEqual(expectedAddonFeatures.Length, mayProperty.AddonFeatures.Count); Assert.IsTrue(mayProperty.AddonFeatures.All(p => expectedAddonFeatures.Contains(p))); Assert.IsTrue(expectedAddonFeatures.All(p => mayProperty.AddonFeatures.Contains(p))); Assert.IsNull(mayProperty.TestHookReliabilityLevel); } else if (isAugModel) { augProperty = (PropertyAugust2017)((StandAloneInstallerJSONModelAugust2017)jsonConfig).Properties; Assert.AreEqual(expectedAddonFeatures.Length, augProperty.AddonFeatures.Count); Assert.IsTrue(augProperty.AddonFeatures.All(p => expectedAddonFeatures.Contains(p))); Assert.IsTrue(expectedAddonFeatures.All(p => augProperty.AddonFeatures.Contains(p))); Assert.IsNull(augProperty.TestHookReliabilityLevel); } else if (isOctModel) { octProperty = (PropertyOctober2017)((StandAloneInstallerJSONModelOctober2017)jsonConfig).Properties; Assert.AreEqual(expectedAddonFeatures.Length, octProperty.AddonFeatures.Count); Assert.IsTrue(octProperty.AddonFeatures.All(p => expectedAddonFeatures.Contains(p))); Assert.IsTrue(expectedAddonFeatures.All(p => octProperty.AddonFeatures.Contains(p))); Assert.IsNull(octProperty.TestHookReliabilityLevel); } // serialization test string newJsonFilePath = Path.Combine(Utility.TestDirectory, "AddonFeatureTestTmpJson.json"); File.WriteAllText(newJsonFilePath, JsonConvert.SerializeObject(jsonConfig, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Populate, PreserveReferencesHandling = PreserveReferencesHandling.None })); StandAloneInstallerJsonModelBase newJsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(newJsonFilePath); File.Delete(newJsonFilePath); if (isAprilModel) { PropertyApril2017 newAprilProperty = (PropertyApril2017)((StandAloneInstallerJSONModelApril2017)newJsonConfig).Properties; Assert.AreEqual(aprilProperty.AddonFeatures.Count, newAprilProperty.AddonFeatures.Count); } else if (isMayModel) { PropertyMay2017 newMayProperty = (PropertyMay2017)((StandAloneInstallerJSONModelMay2017)newJsonConfig).Properties; Assert.AreEqual(mayProperty.AddonFeatures.Count, newMayProperty.AddonFeatures.Count); } else if (isAugModel) { PropertyAugust2017 newAugProperty = (PropertyAugust2017)((StandAloneInstallerJSONModelAugust2017)newJsonConfig).Properties; Assert.AreEqual(augProperty.AddonFeatures.Count, newAugProperty.AddonFeatures.Count); } else if (isOctModel) { PropertyOctober2017 newOctProperty = (PropertyOctober2017)((StandAloneInstallerJSONModelOctober2017)newJsonConfig).Properties; Assert.AreEqual(octProperty.AddonFeatures.Count, newOctProperty.AddonFeatures.Count); } }
public async Task ProcessStartClusterConfigurationUpgradeAsync(ConfigurationUpgradeDescription configUpgradeDesc, TimeSpan timeout, CancellationToken cancellationToken) { /* The cancellation token passed in this API call is not used (by design). This token corresponds to the client side call. * The global this.cancellationToken is initialised in RunAsync() and is honored in every API call. */ UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Entering ProcessStartUpgradeAsync."); try { UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Deserializing input json config string."); StandAloneInstallerJsonModelBase targetJsonConfig = StandAloneInstallerJsonModelBase.GetJsonConfigFromString(configUpgradeDesc.ClusterConfiguration); if (targetJsonConfig == null) { throw new ArgumentException("The input cluster configuration is not in a valid json format or supported apiVersion."); } UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Retrieve current cluster resource from StoreManager."); StandAloneCluster cluster = await this.storeManager.GetClusterResourceAsync( Constants.ClusterReliableDictionaryKey, this.cancellationToken).ConfigureAwait(false); bool isInDataLossState = await DatalossHelper.IsInDatalossStateAsync(this.cancellationToken).ConfigureAwait(false); if (!isInDataLossState) { if (cluster == null || cluster.Current == null) { UpgradeOrchestrationTrace.TraceSource.WriteWarning(TraceType, "Persisted cluster resource is not ready: {0}", cluster == null ? "null" : "current = null"); throw new FabricException("UpgradeOrchestrationService is not ready."); } UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Setting target config and topology based on new input json config."); if (cluster.Pending != null && !this.IsInterruptibleAsync(cluster.Pending).Result) { throw new FabricException(string.Format("Cluster configuration upgrade of type {0} is already in progress and cannot be interrupted.", cluster.Pending.GetType().Name)); } StandaloneSettingsValidator validator = new StandaloneSettingsValidator(targetJsonConfig); await UpgradeOrchestrationMessageProcessor.ValidateModel(targetJsonConfig, validator, cluster, true).ConfigureAwait(false); var removedNodes = validator.GetRemovedNodes(cluster.Topology); var addedNodes = validator.GetAddedNodes(cluster.Topology); if (addedNodes.Any() && StandaloneUtility.CheckFabricRunningAsGMSA(cluster.Current.CSMConfig)) { /* Need to resolve assembly so that FabricDeployer can load the right binaries from FabricCodePath since not all binaries required by FabricDeployer are present in UOS.Current folder.*/ AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(this.LoadFromFabricCodePath); try { await this.PerformAddNodeOperationGMSAAsync(addedNodes, this.fabricClient, validator.ClusterProperties.NodeTypes).ConfigureAwait(false); } catch (AggregateException ex) { UpgradeOrchestrationTrace.TraceSource.WriteError(TraceType, "Adding nodes for GMSA scenario failed with exception: {0}", ex); throw; } finally { AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(this.LoadFromFabricCodePath); } } if (addedNodes.Any()) { cluster.TargetNodeConfig = GetTargetNodeConfigAddNode(validator.Topology, cluster.Current.NodeConfig.Version); } if (removedNodes.Any()) { cluster.TargetNodeConfig = GetTargetNodeConfigRemoveNode(cluster.Topology, removedNodes, cluster.Current.NodeConfig.Version); } else { cluster.Topology = validator.Topology; } cluster.TargetCsmConfig = validator.ClusterProperties; // Cluster is updated above so persist it. await this.storeManager.PersistClusterResourceAsync(Constants.ClusterReliableDictionaryKey, cluster, cancellationToken).ConfigureAwait(false); await this.UpdatePersistedCodeUpgradePackage(validator).ConfigureAwait(false); UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Invoking Orchestrator"); await this.orchestrator.StartUpgradeAsync(cluster, this.cancellationToken, configUpgradeDesc).ContinueWith(t => { if (t.Exception != null) { UpgradeOrchestrationTrace.TraceSource.WriteWarning(TraceType, "Orchestrator completed with status: {0} exception: {1}", t.Status, t.Exception); } else { UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Orchestrator completed with status: {0}", t.Status); } }); } else { StandaloneSettingsValidator validator = new StandaloneSettingsValidator(targetJsonConfig); await UpgradeOrchestrationMessageProcessor.ValidateModel(targetJsonConfig, validator, cluster, false).ConfigureAwait(false); cluster = FabricUpgradeOrchestrationService.ConstructClusterFromJson(targetJsonConfig, FabricNativeConfigStore.FabricGetConfigStore()); DatalossHelper.DryRunConfigUpgrade(cluster); await this.storeManager.PersistClusterResourceAsync(Constants.ClusterReliableDictionaryKey, cluster, this.cancellationToken); await DatalossHelper.UpdateHeathStateAsync(isHealthy : true).ConfigureAwait(false); } } catch (Exception e) { UpgradeOrchestrationTrace.TraceSource.WriteWarning(TraceType, "ProcessStartUpgradeAsync exception: {0}", e); throw UpgradeOrchestrationMessageProcessor.ConvertToComException(e); } UpgradeOrchestrationTrace.TraceSource.WriteInfo(TraceType, "Exiting ProcessStartUpgradeAsync."); }
internal static AnalysisSummary AnalyzeClusterSetup( string configPath, string oldConfigPath, string cabPath, bool usingClusterManifest = false, FabricPackageType fabricPackageType = FabricPackageType.XCopyPackage, bool isForcedRun = false, int maxPercentFailedNodes = 0) { SFDeployerTrace.WriteInfo(StringResources.Info_BPAStart); var summary = new AnalysisSummary(); // Check user has local admin privilege summary.LocalAdminPrivilege = CheckLocalAdminPrivilege(); // Validate JSON config StandAloneInstallerJsonModelBase standAloneModel = null; StandAloneInstallerJsonModelBase oldStandAloneModel = null; if (!usingClusterManifest) { standAloneModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(configPath); if (!string.IsNullOrEmpty(oldConfigPath)) { oldStandAloneModel = StandAloneInstallerJsonModelBase.GetJsonConfigFromFile(oldConfigPath); } summary.IsJsonValid = IsJsonConfigModelValid(standAloneModel, oldStandAloneModel, validateDownNodes: true, throwIfError: false) && ValidateCodeVersionExists(standAloneModel); } // Deliberately not checking empty. Some invocations aren't intended to test cabPath. if (cabPath != null) { summary.IsCabValid = CheckIsCabFile(cabPath); } // Below depends on JSON being valid if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } // Get machine names from JSON config IEnumerable <string> healthyMachineNames = usingClusterManifest ? StandaloneUtility.GetMachineNamesFromClusterManifest(configPath) : standAloneModel.GetClusterTopology().Machines; MachineHealthContainer machineHealthContainer = new MachineHealthContainer(healthyMachineNames, maxPercentFailedNodes); // Validate machine FQDNs, Check SMB ports opened summary.RequiredPortsOpen = StandaloneUtility.CheckRequiredPorts(machineHealthContainer); // Below depends on machines being reachable if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } // Validate Remote Registry Service is not disabled on all machines summary.RemoteRegistryAvailable = CheckRemoteRegistryEnabled(machineHealthContainer); // Below depends on remote registry service if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } summary.FirewallAvailable = CheckFirewallEnabled(machineHealthContainer); // Below depends on firewall service if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } // Run RPC check to validate end-to-end registry access to all machines summary.RpcCheckPassed = CheckRPCAccess(machineHealthContainer); // Below depend on remote registry access if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } summary.NoDomainController = CheckNoMachineIsDomainController(machineHealthContainer); // Below depends on machines not being domain controller if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } if (fabricPackageType == FabricPackageType.XCopyPackage) { // Validate that Fabric runtime MSI is not installed since this will be conflicting with Standalone summary.NoConflictingInstallations = !StandaloneUtility.IsMsiInstalled(machineHealthContainer); } string fabricDataRoot = null; string fabricLogRoot = null; if (!usingClusterManifest) { if (string.IsNullOrEmpty(oldConfigPath)) { summary.FabricInstallable = CheckForCleanInstall(standAloneModel, machineHealthContainer, isForcedRun); // Fabric is not installed on target machines } var importantSettings = standAloneModel.GetFabricSystemSettings(); fabricDataRoot = importantSettings.ContainsKey(DMConstants.FabricDataRootString) ? importantSettings[DMConstants.FabricDataRootString] : null; fabricLogRoot = importantSettings.ContainsKey(DMConstants.FabricLogRootString) ? importantSettings[DMConstants.FabricLogRootString] : null; summary.DataDrivesAvailable = CheckDataSystemDrives(machineHealthContainer, fabricDataRoot, fabricLogRoot); // System drives for path-based settings, exist on target machines // Below depend on data system drives if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } } summary.DrivesEnoughAvailableSpace = CheckDrivesAvailableSpace(machineHealthContainer, fabricDataRoot, fabricLogRoot); // Below depend on root drives having enough space available if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } summary.IsAllOrNoneIOTDevice = CheckAllIOTDevices(machineHealthContainer); // Below depend on all or none machines being IOT Devices if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } // Check dotnet.exe exists in %Path% // Currently we only need to check for IOTCore environment. summary.DotNetExeInPath = IsDotNetExeInPath(machineHealthContainer); // Below depend on IOT Devices having dotnet.exe in path if (!summary.Passed) { SFDeployerTrace.WriteError(StringResources.Error_BPABailing); return(summary); } summary.MachineHealthContainer = machineHealthContainer; LogResult(summary); return(summary); }