public void SetNextState(ServiceFabricAutopilotAgentState nextState, bool toIgnoreStateTransitionWhenStopping = true)
        {
            lock (this.StatusLock)
            {
                if (toIgnoreStateTransitionWhenStopping && this.State < ServiceFabricAutopilotAgentState.Started)
                {
                    TextLogger.LogVerbose("Application is stopping. Ignore state transition request to {0}.", nextState);

                    return;
                }

                TextLogger.LogInfo("State transition: {0} -> {1}", this.State, nextState);

                this.State = nextState;
            }
        }
        private bool ComputeNextStateFromManagingNetworkConfigurationState(out ServiceFabricAutopilotAgentState nextState)
        {
            nextState = ServiceFabricAutopilotAgentState.None;

            try
            {
                bool serviceFabricNodeConfigurationCompleted = Utilities.IsWindowsFabricNodeConfigurationCompleted(false);

                TextLogger.LogInfo("Service Fabric node configuration completed locally :  {0}.", serviceFabricNodeConfigurationCompleted);

                if (!serviceFabricNodeConfigurationCompleted)
                {
                    nextState = ServiceFabricAutopilotAgentState.InstallingProduct;
                }
                else
                {
                    ServiceController fabricHostService = this.localNodeManager.GetInstalledService(Constants.FabricHostServiceName);

                    if (fabricHostService == null)
                    {
                        // TODO: consider assert instead of an error message
                        TextLogger.LogError("Service Fabric node configuration has completed locally while Fabric host service does not exist.");

                        return(false);
                    }

                    if (fabricHostService.Status != ServiceControllerStatus.Running)
                    {
                        nextState = ServiceFabricAutopilotAgentState.StartingNode;
                    }
                    else
                    {
                        nextState = ServiceFabricAutopilotAgentState.NodeStarted;
                    }
                }

                return(true);
            }
            catch (Exception e)
            {
                TextLogger.LogError("Failed to compute next state from {0} state : {1}", ServiceFabricAutopilotAgentState.ManagingNetworkConfiguration, e);

                return(false);
            }
        }
        private bool RunStateMachineCore(ServiceFabricAutopilotAgentState currentState)
        {
            TextLogger.LogInfo("Starting RunStateMachineCore. Current state : {0}.", currentState);

            switch (currentState)
            {
            case ServiceFabricAutopilotAgentState.ManagingNetworkConfiguration:
            {
                if (!this.localNodeManager.ManageNetworkConfiguration())
                {
                    return(false);
                }

                ServiceFabricAutopilotAgentState nextState;
                if (!this.ComputeNextStateFromManagingNetworkConfigurationState(out nextState))
                {
                    return(false);
                }

                this.agentStatus.SetNextState(nextState);

                break;
            }

            case ServiceFabricAutopilotAgentState.InstallingProduct:
            {
                if (!this.localNodeManager.InstallProduct())
                {
                    return(false);
                }

                // For now, we assume the topology is static.
                // TODO: when adding dynamic topology support, change state machine transition here.
                this.agentStatus.SetNextState(ServiceFabricAutopilotAgentState.DiscoveringTopology);

                break;
            }

            case ServiceFabricAutopilotAgentState.DiscoveringTopology:
            {
                ClusterTopology expectedTopology;
                if (!this.localNodeManager.DiscoverTopology(out expectedTopology))
                {
                    return(false);
                }

                lock (this.agentStatus.StatusLock)
                {
                    this.agentStatus.ExpectedTopology = expectedTopology;

                    this.agentStatus.ExpectedTopologyRunning = false;
                }

                this.agentStatus.SetNextState(ServiceFabricAutopilotAgentState.ConfiguringNode);

                break;
            }

            case ServiceFabricAutopilotAgentState.ConfiguringNode:
            {
                ClusterTopology topologyToDeploy = this.agentStatus.GetTopologyToDeploy();

                if (!this.localNodeManager.ConfigureLocalNode(topologyToDeploy))
                {
                    return(false);
                }

                lock (this.agentStatus.StatusLock)
                {
                    this.agentStatus.DeployedTopology = topologyToDeploy;

                    this.agentStatus.ExpectedTopologyRunning = !this.agentStatus.DeployedTopology.IsClusterTopologyChanged(this.agentStatus.ExpectedTopology);
                }

                this.agentStatus.SetNextState(ServiceFabricAutopilotAgentState.StartingNode);

                break;
            }

            case ServiceFabricAutopilotAgentState.StartingNode:
            {
                if (!this.localNodeManager.StartLocalNode())
                {
                    return(false);
                }

                this.agentStatus.SetNextState(ServiceFabricAutopilotAgentState.NodeStarted);

                break;
            }

            case ServiceFabricAutopilotAgentState.NodeStarted:
            {
                // TODO: this only applies when DynamicTopologyUpdateMode == None or OnNodeConfigurationOnly.
                // When we want to update topology whenever topology changes, this needs to change.
                lock (this.agentStatus.StatusLock)
                {
                    this.agentStatus.ExpectedTopologyRunning = true;
                    this.agentStatus.ExpectedTopology        = ClusterTopology.GetClusterTopology();
                    this.agentStatus.DeployedTopology        = this.agentStatus.ExpectedTopology;
                }

                break;
            }
            }

            return(true);
        }