private void DoPrepareDeploymentToClusteredEnvironment(EnvironmentInfo environmentInfo, Lazy <string> artifactsBinariesDirPathProvider)
        {
            string clusterGroupName = environmentInfo.GetFailoverClusterGroupNameForProject(DeploymentInfo.ProjectName);

            if (string.IsNullOrEmpty(clusterGroupName))
            {
                throw new InvalidOperationException(string.Format("There is no cluster group defined for project '{0}' in environment '{1}'.", DeploymentInfo.ProjectName, environmentInfo.Name));
            }

            string failoverClusterMachineName = environmentInfo.FailoverClusterMachineName;

            if (string.IsNullOrEmpty(failoverClusterMachineName))
            {
                throw new InvalidOperationException(string.Format("Environment '{0}' has no failover cluster machine name defined.", environmentInfo.Name));
            }

            string currentNodeName =
                _failoverClusterManager.GetCurrentNodeName(failoverClusterMachineName, clusterGroupName);

            if (string.IsNullOrEmpty(currentNodeName))
            {
                throw new InvalidOperationException(string.Format("Cluster group '{0}' has no current node in a cluster '{1}' in environment '{2}'.", clusterGroupName, environmentInfo.FailoverClusterMachineName, environmentInfo.Name));
            }

            PostDiagnosticMessage(string.Format("Current node: '{0}'.", currentNodeName), DiagnosticMessageType.Trace);

            List <string> possibleNodeNames =
                _failoverClusterManager.GetPossibleNodeNames(failoverClusterMachineName, clusterGroupName)
                .ToList();

            PostDiagnosticMessage(string.Format("Possible nodes: {0}.", string.Join(", ", possibleNodeNames.Select(n => string.Format("'{0}'", n)))), DiagnosticMessageType.Trace);

            if (possibleNodeNames.Count < 2)
            {
                throw new InvalidOperationException(string.Format("There is only one possible node for cluster group '{0}' in a cluster '{1}' in environment '{2}'.", clusterGroupName, environmentInfo.FailoverClusterMachineName, environmentInfo.Name));
            }

            // update nt service on all machines other than current owner node
            CollectedCredentials cachedCollectedCredentials = null;

            Func <string, Func <CollectedCredentials> > collectCredentialsFunc =
                machineName =>
                () =>
            {
                // ReSharper disable AccessToModifiedClosure
                if (cachedCollectedCredentials != null)
                {
                    return(cachedCollectedCredentials);
                }
                // ReSharper restore AccessToModifiedClosure

                if (UseLocalSystemUser)
                {
                    cachedCollectedCredentials = new CollectedCredentials(LocalSystemUserName);
                }
                else
                {
                    EnvironmentUser environmentUser =
                        environmentInfo.GetEnvironmentUser(_projectInfo.NtServiceUserId);

                    string environmentUserPassword =
                        PasswordCollectorHelper.CollectPasssword(
                            _passwordCollector,
                            DeploymentInfo.DeploymentId,
                            environmentInfo,
                            machineName,
                            environmentUser,
                            OnDiagnosticMessagePosted);

                    cachedCollectedCredentials =
                        new CollectedCredentials(
                            environmentUser.UserName,
                            environmentUserPassword);
                }

                return(cachedCollectedCredentials);
            };

            foreach (string possibleNodeName in possibleNodeNames)
            {
                string machineName = possibleNodeName;

                if (string.Equals(machineName, currentNodeName, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                DoPrepareCommonDeploymentSteps(
                    _projectInfo.NtServiceName,
                    machineName,
                    environmentInfo.NtServicesBaseDirPath,
                    absoluteLocalPath => EnvironmentInfo.GetNetworkPath(machineName, absoluteLocalPath),
                    artifactsBinariesDirPathProvider,
                    collectCredentialsFunc(machineName),
                    false);
            }

            // move cluster group to another node
            string targetNodeName =
                possibleNodeNames.FirstOrDefault(nodeName => nodeName != currentNodeName);

            PostDiagnosticMessage(string.Format("Target node: '{0}'.", targetNodeName), DiagnosticMessageType.Trace);

            if (string.IsNullOrEmpty(targetNodeName))
            {
                throw new InvalidOperationException(string.Format("There is no node in cluster '{0}' that we can move cluster group '{1}' to.", failoverClusterMachineName, clusterGroupName));
            }

            AddSubTask(
                new MoveClusterGroupToAnotherNodeDeploymentStep(
                    _failoverClusterManager,
                    failoverClusterMachineName,
                    clusterGroupName,
                    targetNodeName));

            // update nt service on the machine that was the previous owner node
            string previousMachineName = currentNodeName;

            DoPrepareCommonDeploymentSteps(
                _projectInfo.NtServiceName,
                previousMachineName,
                environmentInfo.NtServicesBaseDirPath,
                absoluteLocalPath => EnvironmentInfo.GetNetworkPath(previousMachineName, absoluteLocalPath),
                artifactsBinariesDirPathProvider,
                collectCredentialsFunc(previousMachineName),
                false);
        }
        private void DoPrepareCommonDeploymentSteps(string ntServiceName, string appServerMachineName, string ntServicesBaseDirPath, Func <string, string> getAppServerNetworkPathFunc, Lazy <string> artifactsBinariesDirPathProvider, Func <CollectedCredentials> collectCredentialsFunc, bool startServiceAfterDeployment)
        {
            // check if the service is present on the target machine
            bool serviceExists =
                _ntServiceManager
                .DoesServiceExist(appServerMachineName, ntServiceName);

            if (serviceExists)
            {
                // create a step for stopping the service
                AddSubTask(
                    new StopNtServiceDeploymentStep(
                        _ntServiceManager,
                        appServerMachineName,
                        _projectInfo.NtServiceName));
            }

            // create a step for copying the binaries to the target machine
            string targetDirPath = Path.Combine(ntServicesBaseDirPath, _projectInfo.NtServiceDirName);

            /* // TODO IMM HI: xxx we don't need this for now - should we parameterize this somehow?
             *    // create a backup step if needed
             *    string targetDirNetworkPath = getAppServerNetworkPathFunc(targetDirPath);
             *
             *    if (Directory.Exists(targetDirNetworkPath))
             *    {
             *      AddSubTask(
             *        new BackupFilesDeploymentStep(
             *          targetDirNetworkPath));
             *    }
             */

            string[] excludedDirs = string.IsNullOrEmpty(_projectInfo.ExtensionsDirName)
        ? new string[0]
        : new string[] { _projectInfo.ExtensionsDirName };

            AddSubTask(
                new CleanDirectoryDeploymentStep(
                    _directoryAdapter,
                    _fileAdapter,
                    new Lazy <string>(() => getAppServerNetworkPathFunc(targetDirPath)),
                    excludedDirs: excludedDirs));

            AddSubTask(
                new CopyFilesDeploymentStep(
                    _directoryAdapter,
                    artifactsBinariesDirPathProvider,
                    new Lazy <string>(() => getAppServerNetworkPathFunc(targetDirPath))));

            if (!serviceExists)
            {
                // collect credentials
                CollectedCredentials collectedCredentials = collectCredentialsFunc();

                // create a step for installing the service,
                string serviceExecutablePath = Path.Combine(targetDirPath, _projectInfo.NtServiceExeName);

                var ntServiceDescriptor =
                    new NtServiceDescriptor(
                        _projectInfo.NtServiceName,
                        serviceExecutablePath,
                        ServiceAccount.NetworkService,
                        ServiceStartMode.Automatic,
                        _projectInfo.NtServiceDisplayName,
                        collectedCredentials.UserName,
                        collectedCredentials.Password);

                AddSubTask(
                    new InstallNtServiceDeploymentStep(
                        _ntServiceManager,
                        appServerMachineName,
                        ntServiceDescriptor));
            }

            if (startServiceAfterDeployment)
            {
                // create a step for starting the service
                AddSubTask(
                    new StartNtServiceDeploymentStep(
                        _ntServiceManager,
                        appServerMachineName,
                        _projectInfo.NtServiceName));
            }
        }
        private void DoPrepareDeploymentToClusteredEnvironment(EnvironmentInfo environmentInfo, Lazy<string> artifactsBinariesDirPathProvider)
        {
            string clusterGroupName = environmentInfo.GetFailoverClusterGroupNameForProject(DeploymentInfo.ProjectName);

              if (string.IsNullOrEmpty(clusterGroupName))
              {
            throw new InvalidOperationException(string.Format("There is no cluster group defined for project '{0}' in environment '{1}'.", DeploymentInfo.ProjectName, environmentInfo.Name));
              }

              string failoverClusterMachineName = environmentInfo.FailoverClusterMachineName;

              if (string.IsNullOrEmpty(failoverClusterMachineName))
              {
            throw new InvalidOperationException(string.Format("Environment '{0}' has no failover cluster machine name defined.", environmentInfo.Name));
              }

              string currentNodeName =
            _failoverClusterManager.GetCurrentNodeName(failoverClusterMachineName, clusterGroupName);

              if (string.IsNullOrEmpty(currentNodeName))
              {
            throw new InvalidOperationException(string.Format("Cluster group '{0}' has no current node in a cluster '{1}' in environment '{2}'.", clusterGroupName, environmentInfo.FailoverClusterMachineName, environmentInfo.Name));
              }

              PostDiagnosticMessage(string.Format("Current node: '{0}'.", currentNodeName), DiagnosticMessageType.Trace);

              List<string> possibleNodeNames =
            _failoverClusterManager.GetPossibleNodeNames(failoverClusterMachineName, clusterGroupName)
              .ToList();

              PostDiagnosticMessage(string.Format("Possible nodes: {0}.", string.Join(", ", possibleNodeNames.Select(n => string.Format("'{0}'", n)))), DiagnosticMessageType.Trace);

              if (possibleNodeNames.Count < 2)
              {
            throw new InvalidOperationException(string.Format("There is only one possible node for cluster group '{0}' in a cluster '{1}' in environment '{2}'.", clusterGroupName, environmentInfo.FailoverClusterMachineName, environmentInfo.Name));
              }

              // update nt service on all machines other than current owner node
              CollectedCredentials cachedCollectedCredentials = null;

              Func<string, Func<CollectedCredentials>> collectCredentialsFunc =
            machineName =>
            () =>
            {
              // ReSharper disable AccessToModifiedClosure
              if (cachedCollectedCredentials != null)
              {
            return cachedCollectedCredentials;
              }
              // ReSharper restore AccessToModifiedClosure

              if (UseLocalSystemUser)
              {
            cachedCollectedCredentials = new CollectedCredentials(LocalSystemUserName);
              }
              else
              {
            EnvironmentUser environmentUser =
              environmentInfo.GetEnvironmentUser(_projectInfo.NtServiceUserId);

            string environmentUserPassword =
              PasswordCollectorHelper.CollectPasssword(
                _passwordCollector,
                DeploymentInfo.DeploymentId,
                environmentInfo,
                machineName,
                environmentUser,
                OnDiagnosticMessagePosted);

            cachedCollectedCredentials =
              new CollectedCredentials(
                environmentUser.UserName,
                environmentUserPassword);
              }

              return cachedCollectedCredentials;
            };

              foreach (string possibleNodeName in possibleNodeNames)
              {
            string machineName = possibleNodeName;

            if (string.Equals(machineName, currentNodeName, StringComparison.OrdinalIgnoreCase))
            {
              continue;
            }

            DoPrepareCommonDeploymentSteps(
              _projectInfo.NtServiceName,
              machineName,
              environmentInfo.NtServicesBaseDirPath,
              absoluteLocalPath => EnvironmentInfo.GetNetworkPath(machineName, absoluteLocalPath),
              artifactsBinariesDirPathProvider,
              collectCredentialsFunc(machineName),
              false);
              }

              // move cluster group to another node
              string targetNodeName =
            possibleNodeNames.FirstOrDefault(nodeName => nodeName != currentNodeName);

              PostDiagnosticMessage(string.Format("Target node: '{0}'.", targetNodeName), DiagnosticMessageType.Trace);

              if (string.IsNullOrEmpty(targetNodeName))
              {
            throw new InvalidOperationException(string.Format("There is no node in cluster '{0}' that we can move cluster group '{1}' to.", failoverClusterMachineName, clusterGroupName));
              }

              AddSubTask(
            new MoveClusterGroupToAnotherNodeDeploymentStep(
              _failoverClusterManager,
              failoverClusterMachineName,
              clusterGroupName,
              targetNodeName));

              // update nt service on the machine that was the previous owner node
              string previousMachineName = currentNodeName;

              DoPrepareCommonDeploymentSteps(
            _projectInfo.NtServiceName,
            previousMachineName,
            environmentInfo.NtServicesBaseDirPath,
            absoluteLocalPath => EnvironmentInfo.GetNetworkPath(previousMachineName, absoluteLocalPath),
            artifactsBinariesDirPathProvider,
            collectCredentialsFunc(previousMachineName),
            false);
        }