Esempio n. 1
0
        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
            };
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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.");
        }
Esempio n. 4
0
        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.");
        }
Esempio n. 5
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);
            }
        }
Esempio n. 6
0
        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;
            }
        }
Esempio n. 7
0
        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);
            }
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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));
        }
Esempio n. 10
0
        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);
        }
Esempio n. 12
0
        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.");
        }
Esempio n. 13
0
        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.");
        }
Esempio n. 14
0
        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");
        }
Esempio n. 15
0
        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);
            }
        }
Esempio n. 16
0
        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);
            }
        }
        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);
        }