private void ValidateInfrastructureWithStaticTopologyProvider(ClusterManifestTypeInfrastructureWindowsAzureStaticTopology azureStaticTopologyInfrastructure)
 {
     foreach (ClusterManifestTypeNodeType nodeType in this.clusterManifest.NodeTypes)
     {
         if (nodeType.Endpoints == null)
         {
             throw new ArgumentException(
                       String.Format(
                           "Endpoint section was not defined by node type {0}. The section has to be defined for all node types when staticTopologyProvider is used on Windows Azure infrastructure.",
                           nodeType.Name));
         }
     }
 }
        private void LogClusterTopology(ClusterManifestTypeInfrastructureWindowsAzureStaticTopology clusterTopology)
        {
            TextLogger.LogInfo("Cluster topology from static topology provider:");

            TextLogger.LogInfo("NodeName, NodeType, IsSeedNode, UpgradeDomain, FaultDomain, IPAddressOrFQDN");

            foreach (FabricNodeType node in clusterTopology.NodeList)
            {
                TextLogger.LogInfo(
                    "{0}, {1}, {2}, {3}, {4}, {5}",
                    node.NodeName,
                    node.NodeTypeRef,
                    node.IsSeedNode,
                    node.UpgradeDomain,
                    node.FaultDomain,
                    node.IPAddressOrFQDN
                    );
            }
        }
        private void InitializeFromStaticTopologyProvider(ClusterManifestTypeInfrastructureWindowsAzureStaticTopology azureStaticTopologyInfrastructure, InfrastructureNodeType[] inputInfrastructureNodes, Dictionary <string, ClusterManifestTypeNodeType> nameToNodeTypeMap)
        {
            // For static topology provider, source of cluster topology is the cluster manifest while infrastructure manifest is not used in the case.
            // Seed nodes are determined by IsSeedNode attribute for each node element.
            foreach (var nodeInfo in azureStaticTopologyInfrastructure.NodeList)
            {
                var nodeType = nameToNodeTypeMap[nodeInfo.NodeTypeRef];
                var node     = (new InfrastructureNodeType()
                {
                    Certificates = nodeType.Certificates,
                    Endpoints = nodeType.Endpoints,
                    FaultDomain = nodeInfo.FaultDomain,
                    IPAddressOrFQDN = nodeInfo.IPAddressOrFQDN,
                    IsSeedNode = nodeInfo.IsSeedNode,
                    NodeName = nodeInfo.NodeName,
                    NodeTypeRef = nodeInfo.NodeTypeRef,
                    RoleOrTierName = nodeInfo.NodeTypeRef,
                    UpgradeDomain = nodeInfo.UpgradeDomain
                });

                this.nodes.Add(node);

                if (node.IsSeedNode)
                {
                    // Add vote mappings
                    string connectionAddress = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", node.IPAddressOrFQDN, node.Endpoints.ClusterConnectionEndpoint.Port);
                    this.voteMappings.Add(node.NodeName, connectionAddress);
                    FabricValidator.TraceSource.WriteNoise(FabricValidatorUtility.TraceTag, "Mapping {0}-{1} added", node.NodeName, connectionAddress);

                    // Add votes.
                    string key   = node.NodeName;
                    string value = string.Format(CultureInfo.InvariantCulture, "{0},{1}", "WindowsAzure", node.NodeName);
                    this.votes.Add(new SettingsTypeSectionParameter()
                    {
                        Name = key, Value = value, MustOverride = false
                    });
                    FabricValidator.TraceSource.WriteNoise(FabricValidatorUtility.TraceTag, "Vote {0}-{1} added", key, value);
                }
            }

            this.isScaleMin = FabricValidatorUtility.IsAddressLoopback(nodes[0].IPAddressOrFQDN);
        }
        internal static void CompareAndAnalyze(ClusterManifestType currentClusterManifest, ClusterManifestType targetClusterManifest, Infrastructure infrastructure, DeploymentParameters parameters)
        {
            // If the infrastructure elements are different, the update cannot continue
            if (targetClusterManifest.Infrastructure.Item.GetType() != currentClusterManifest.Infrastructure.Item.GetType())
            {
                DeployerTrace.WriteError("Invalid Operation. Cannot update from 1 infrastructure type to another");
                throw new ClusterManifestValidationException(StringResources.Error_FabricDeployer_InvalidClusterManifest_Formatted);
            }

            // Validate that the new cluster manifest and the node list are valid
            try
            {
                var currentWindowsFabricSettings = new WindowsFabricSettings(currentClusterManifest);
                var targetWindowsFabricSettings  = new WindowsFabricSettings(targetClusterManifest);
                FabricValidator.Create(targetClusterManifest, infrastructure.InfrastructureNodes, targetWindowsFabricSettings, parameters.Operation).Validate();
                //Validate if the SeedNodeCount increases by one
                int           currentSeedNodes = 0, targetSeedNodes = 0;
                List <String> currentSeedNodesList = new List <String>();
                List <String> targetSeedNodesList  = new List <String>();
                if (currentClusterManifest.Infrastructure.Item is ClusterManifestTypeInfrastructureWindowsAzure)
                {
                    ClusterManifestTypeInfrastructureWindowsAzure currentInfrastructure = currentClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureWindowsAzure;
                    ClusterManifestTypeInfrastructureWindowsAzure targetInfrastructure  = targetClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureWindowsAzure;
                    for (int i = 0; i < currentInfrastructure.Roles.Length; i++)
                    {
                        currentSeedNodes += currentInfrastructure.Roles[i].SeedNodeCount;
                    }
                    for (int j = 0; j < targetInfrastructure.Roles.Length; j++)
                    {
                        targetSeedNodes += targetInfrastructure.Roles[j].SeedNodeCount;
                    }
                }
                else if (currentClusterManifest.Infrastructure.Item is ClusterManifestTypeInfrastructureWindowsAzureStaticTopology)
                {
                    ClusterManifestTypeInfrastructureWindowsAzureStaticTopology currentInfrastructure = currentClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureWindowsAzureStaticTopology;
                    ClusterManifestTypeInfrastructureWindowsAzureStaticTopology targetInfrastructure  = targetClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureWindowsAzureStaticTopology;
                    foreach (FabricNodeType nodelist in currentInfrastructure.NodeList)
                    {
                        if (nodelist.IsSeedNode)
                        {
                            currentSeedNodes++;
                        }
                    }
                    foreach (FabricNodeType nodelist in targetInfrastructure.NodeList)
                    {
                        if (nodelist.IsSeedNode)
                        {
                            targetSeedNodes++;
                        }
                    }
                }
#if DotNetCoreClrLinux
                else if (currentClusterManifest.Infrastructure.Item is ClusterManifestTypeInfrastructureLinux)
                {
                    var currentInfrastructure = currentClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureLinux;
                    var targetInfrastructure  = targetClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureLinux;
#else
                else if (currentClusterManifest.Infrastructure.Item is ClusterManifestTypeInfrastructureWindowsServer)
                {
                    var currentInfrastructure = currentClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureWindowsServer;
                    var targetInfrastructure  = targetClusterManifest.Infrastructure.Item as ClusterManifestTypeInfrastructureWindowsServer;
#endif
                    foreach (FabricNodeType nodelist in currentInfrastructure.NodeList)
                    {
                        if (nodelist.IsSeedNode)
                        {
                            currentSeedNodes++;
                            currentSeedNodesList.Add(nodelist.NodeName);
                        }
                    }
                    foreach (FabricNodeType nodelist in targetInfrastructure.NodeList)
                    {
                        if (nodelist.IsSeedNode)
                        {
                            targetSeedNodes++;
                            targetSeedNodesList.Add(nodelist.NodeName);
                        }
                    }
                }
                if (System.Math.Abs(currentSeedNodes - targetSeedNodes) > 1)
                {
                    DeployerTrace.WriteError(StringResources.Warning_SeedNodeCountCanOnlyChangeByOne);
                    throw new ClusterManifestValidationException(StringResources.Warning_SeedNodeCountCanOnlyChangeByOne);
                }
                else if (currentSeedNodesList.Except(targetSeedNodesList).Union(targetSeedNodesList.Except(currentSeedNodesList)).Count() > 1)
                {
                    DeployerTrace.WriteError(StringResources.Warning_SeedNodeSetCannotHaveMultipleChanges);
                    throw new ClusterManifestValidationException(StringResources.Warning_SeedNodeSetCannotHaveMultipleChanges);
                }

                var fabricValidator = FabricValidator.Create(currentClusterManifest, null, currentWindowsFabricSettings, parameters.Operation);
                // Finally, compare the settings and decide if fabric must restart or not
                IEnumerable <KeyValuePair <string, string> > modifiedStaticSettings = fabricValidator.CompareAndAnalyze(targetClusterManifest, parameters.NodeTypeName);
                if (modifiedStaticSettings.Count() > 0)
                {
                    WriteModifiedStaticSettingsToFile(modifiedStaticSettings, targetClusterManifest.FabricSettings, parameters.OutputFile);
                    throw new FabricHostRestartRequiredException("Fabric host restart is required");
                }
                else
                {
                    throw new FabricHostRestartNotRequiredException("Fabric host restart is not required");
                }
            }
            catch (Exception e)
            {
                if (e is FabricHostRestartRequiredException || e is FabricHostRestartNotRequiredException)
                {
                    throw e;
                }
                else
                {
                    throw new ClusterManifestValidationException(
                              string.Format(StringResources.Error_FabricDeployer_InvalidClusterManifest_Formatted, e));
                }
            }
        }
        public bool DiscoverTopology(out ClusterTopology expectedTopology)
        {
            expectedTopology = null;

            try
            {
                TextLogger.LogInfo("Discovering cluster topology from bootstrap cluster manifest file.");

                if (ConfigurationManager.BootstrapClusterManifestLocation == BootstrapClusterManifestLocationType.NotReady)
                {
                    TextLogger.LogWarning("Bootstrap cluster manifest is not ready. Cluster topology would not be discovered until bootstrap cluster manifest is ready.");

                    return(false);
                }

                ClusterManifestType bootstrapClusterManifest;
                if (!this.ReadBootstrapClusterManifestFile(out bootstrapClusterManifest))
                {
                    return(false);
                }

                TopologyProviderType topologyProviderType = TopologyProvider.GetTopologyProviderTypeFromClusterManifest(bootstrapClusterManifest);

                TextLogger.LogInfo("Topology provider type : {0}.", topologyProviderType);

                if (topologyProviderType != TopologyProviderType.StaticTopologyProvider)
                {
                    TextLogger.LogInfo("Topology provider type {0} is not supported to provide static topology.", topologyProviderType);

                    return(false);
                }
                else
                {
                    /*
                     * Static topology provider defines the authoritative cluster topology in the cluster manifest.
                     * If the local machine (physical or virtual) is not part of the cluster topology specified in static topology provider section, a Service Fabric node will not be started locally.
                     * During scale-up, bootstrap cluster manifest has to be upgraded to allow new Service Fabric nodes to be started on the new machines and join the ring.
                     * A scale-up is normally a two-phase process with allocation of new machines (and their IPs) and generation of a new bootstrap cluster manifest with updated topology.
                     */
                    ClusterManifestTypeInfrastructureWindowsAzureStaticTopology staticTopologyProviderElement = TopologyProvider.GetStaticTopologyProviderElementFromClusterManifest(bootstrapClusterManifest);

                    if (staticTopologyProviderElement.NodeList == null || staticTopologyProviderElement.NodeList.Length == 0)
                    {
                        TextLogger.LogError("Static topology provider section of bootstrap cluster manifest does not specify topology of the Service Fabric cluster.");

                        return(false);
                    }

                    LogClusterTopology(staticTopologyProviderElement);

                    ClusterTopology staticTopologyProviderClusterTopology = ClusterTopology.GetClusterTopology();

                    staticTopologyProviderClusterTopology.LogTopology();

                    expectedTopology = staticTopologyProviderClusterTopology;

                    TextLogger.LogInfo("Successfully discovered cluster topology.");

                    return(true);
                }
            }
            catch (Exception e)
            {
                TextLogger.LogError("Failed to discover cluster topology : {0}", e);

                return(false);
            }
        }
        private void InitializeFromStaticTopologyProvider(ClusterManifestTypeInfrastructureWindowsAzureStaticTopology azureStaticTopologyInfrastructure, InfrastructureNodeType[] inputInfrastructureNodes, Dictionary <string, ClusterManifestTypeNodeType> nameToNodeTypeMap, DynamicTopologyKind dynamicTopologyKind)
        {
            FabricValidator.TraceSource.WriteInfo(FabricValidatorUtility.TraceTag, "DynamicTopologyKind = {0}", dynamicTopologyKind);

            Dictionary <string, InfrastructureNodeType> infrastructureManifestNodes = null;

            if (dynamicTopologyKind != DynamicTopologyKind.None)
            {
                infrastructureManifestNodes = new Dictionary <string, InfrastructureNodeType>(StringComparer.Ordinal);
                if (inputInfrastructureNodes != null)
                {
                    foreach (var inputInfrastructureNode in inputInfrastructureNodes)
                    {
                        if (!string.IsNullOrWhiteSpace(inputInfrastructureNode.NodeName))
                        {
                            infrastructureManifestNodes[inputInfrastructureNode.NodeName] = inputInfrastructureNode;
                        }
                    }
                }
            }

            // For static topology provider, effective cluster topology is based on the cluster manifest static topology section + infrastructure manifest.
            // When dynamicTopologyKind == DynamicTopologyKind.None, effective cluster topology is solely based on cluster manifest static topology section while infrastructure manifest is not used.
            // When dynamicTopologyKind <> DynamicTopologyKind.None, the information in infrastructure manifest would be used to supplement cluster manifest in determining effective clsuter topology.
            // Seed nodes are determined by IsSeedNode attribute for each node element.
            foreach (var nodeInfo in azureStaticTopologyInfrastructure.NodeList)
            {
                var nodeType = nameToNodeTypeMap[nodeInfo.NodeTypeRef];
                var node     = (new InfrastructureNodeType()
                {
                    Certificates = nodeType.Certificates,
                    Endpoints = nodeType.Endpoints,
                    FaultDomain = nodeInfo.FaultDomain,
                    IPAddressOrFQDN = nodeInfo.IPAddressOrFQDN,
                    IsSeedNode = nodeInfo.IsSeedNode,
                    NodeName = nodeInfo.NodeName,
                    NodeTypeRef = nodeInfo.NodeTypeRef,
                    RoleOrTierName = nodeInfo.NodeTypeRef,
                    UpgradeDomain = nodeInfo.UpgradeDomain
                });

                // Nodes defined in static topology can optionally rely on infrastructure wrappers to provide values for IPAddressOrFQDN, FD, UD etc.
                // Specifically:
                // 1) When a concrete value is defined for IPAddressOrFQDN/FD/UD of a node, the concrete value would always be used.
                // 2) When "*" is defined for IPAddressOrFQDN/FD/UD of a node, the value provided by infrastructure wrappers would be used.
                if ((dynamicTopologyKind & DynamicTopologyKind.NodeTopologyInfoUpdate) == DynamicTopologyKind.NodeTopologyInfoUpdate)
                {
                    if (infrastructureManifestNodes.ContainsKey(node.NodeName))
                    {
                        bool nodeTopologyInfoUpdated    = false;
                        var  infrastructureManifestNode = infrastructureManifestNodes[node.NodeName];

                        if (string.Compare(node.IPAddressOrFQDN, AutomaticTopologyInfoValue, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            node.IPAddressOrFQDN    = infrastructureManifestNode.IPAddressOrFQDN;
                            nodeTopologyInfoUpdated = true;
                        }

                        if (string.Compare(node.UpgradeDomain, AutomaticTopologyInfoValue, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            node.UpgradeDomain      = infrastructureManifestNode.UpgradeDomain;
                            nodeTopologyInfoUpdated = true;
                        }

                        if (string.Compare(node.FaultDomain, AutomaticTopologyInfoValue, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            node.FaultDomain        = infrastructureManifestNode.FaultDomain;
                            nodeTopologyInfoUpdated = true;
                        }

                        infrastructureManifestNodes.Remove(node.NodeName);

                        if (nodeTopologyInfoUpdated)
                        {
                            FabricValidator.TraceSource.WriteNoise(FabricValidatorUtility.TraceTag, "Topology info for node {0} in cluster manifest is updated based infrastructure manifest", node.NodeName);
                        }
                    }
                }

                this.nodes.Add(node);

                if (node.IsSeedNode)
                {
                    // Add vote mappings
                    string connectionAddress = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", node.IPAddressOrFQDN, node.Endpoints.ClusterConnectionEndpoint.Port);
                    this.voteMappings.Add(node.NodeName, connectionAddress);
                    FabricValidator.TraceSource.WriteNoise(FabricValidatorUtility.TraceTag, "Mapping {0}-{1} added", node.NodeName, connectionAddress);

                    // Add votes.
                    string key   = node.NodeName;
                    string value = string.Format(CultureInfo.InvariantCulture, "{0},{1}", "WindowsAzure", node.NodeName);
                    this.votes.Add(new SettingsTypeSectionParameter()
                    {
                        Name = key, Value = value, MustOverride = false
                    });
                    FabricValidator.TraceSource.WriteNoise(FabricValidatorUtility.TraceTag, "Vote {0}-{1} added", key, value);
                }
            }

            this.isScaleMin = FabricValidatorUtility.IsAddressLoopback(nodes[0].IPAddressOrFQDN);
        }