private long GetRemainingInstallationTimeout()
        {
            ExecutorDataForNtService executorDataForNtService = this._nodeAgentSfUtility.GetExecutorDataForNtService();

            if (!executorDataForNtService.ApprovedDateTime.HasValue)
            {
                // This should never happen, as we're reading timeout values only when we're in installation phase, implying rm task has been already approved.
                ServiceEventSource.Current.ErrorMessage("executorDataForNtService.ApprovedDateTime was found to be null");
                throw new InvalidDataException("executorDataForNtService.ApprovedDateTime was found to be null");
            }

            _eventSource.InfoMessage("ExecutorDataForNtService : ApprovedDateTime {0} , ExecutorTimeoutInMinutes {1}", executorDataForNtService.ApprovedDateTime, executorDataForNtService.ExecutorTimeoutInMinutes);
            TimeSpan elapsedTime = DateTime.UtcNow.Subtract(executorDataForNtService.ApprovedDateTime.Value);

            long timeout = elapsedTime.Minutes >= executorDataForNtService.ExecutorTimeoutInMinutes ? 0 : executorDataForNtService.ExecutorTimeoutInMinutes - elapsedTime.Minutes;

            _eventSource.InfoMessage("Timeout for installation process: {0}", timeout);
            return(timeout);
        }
        /// <summary>
        /// Gets the state of Windows Update operation using the state stored in RepairTask
        /// </summary>
        /// <param name="nodeName">Name of current Service Fabric node</param>
        /// <param name="timeout">Timeout for the async operation</param>
        /// <param name="cancellationToken">The cancellation token to cancel the async operation</param>
        /// <returns>A Task representing the asnyc operation, result of the task would be <see cref="NodeAgentSfUtilityExitCodes"/></returns>
        public async Task <NodeAgentSfUtilityExitCodes> GetWuOperationStateAsync(String nodeName, TimeSpan timeout, CancellationToken cancellationToken)
        {
            RepairTask repairTask;

            try
            {
                repairTask =
                    await
                    RepairManagerHelper.GetRepairTaskForNode(
                        this.fabricClient,
                        nodeName,
                        timeout,
                        cancellationToken);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ErrorMessage(
                    String.Format("RepairManagerHelper.GetRepairTaskForNode failed. Exception details {0}", e));
                if (e is FabricTransientException)
                {
                    return(NodeAgentSfUtilityExitCodes.RetryableException);
                }
                else
                {
                    return(NodeAgentSfUtilityExitCodes.Failure);
                }
            }

            if (null == repairTask)
            {
                ServiceEventSource.Current.VerboseMessage(String.Format("No repair task found for this node, Operation State = {0}", NodeAgentSfUtilityExitCodes.None));
                return(NodeAgentSfUtilityExitCodes.None);
            }

            NodeAgentSfUtilityExitCodes resultState;
            ExecutorDataForRmTask       executorData             = SerializationUtility.Deserialize <ExecutorDataForRmTask>(repairTask.ExecutorData);
            ExecutorDataForNtService    executorDataForNtService = new ExecutorDataForNtService()
            {
                ApprovedDateTime = repairTask.ApprovedTimestamp, ExecutorTimeoutInMinutes = executorData.ExecutorTimeoutInMinutes
            };

            string workFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
            string executorDataForNtServiceFilePath = Path.Combine(workFolder, ExecutorDataForNtServiceFileName);

            SerializationUtility.Serialize(executorDataForNtServiceFilePath, executorDataForNtService);

            switch (repairTask.State)
            {
            case RepairTaskState.Claimed:
            case RepairTaskState.Preparing:
                resultState = NodeAgentSfUtilityExitCodes.DownloadCompleted;
                break;

            case RepairTaskState.Approved:
                resultState = NodeAgentSfUtilityExitCodes.InstallationApproved;
                break;

            case RepairTaskState.Executing:
            {
                resultState = executorData.ExecutorSubState;
                if (resultState == NodeAgentSfUtilityExitCodes.RestartRequested)
                {
                    if (this.GetRestartStatus(executorData.RestartRequestedTime))
                    {
                        string resultDetails =
                            "Installation of the updates completed, Restart post installation completed successfully";
                        resultState = await RepairManagerHelper.UpdateRepairTask(this.fabricClient, nodeName,
                                                                                 RepairTaskState.Executing, RepairTaskResult.Pending,
                                                                                 resultDetails, NodeAgentSfUtilityExitCodes.RestartCompleted, timeout,
                                                                                 cancellationToken);

                        if (resultState == NodeAgentSfUtilityExitCodes.Success)
                        {
                            resultState = NodeAgentSfUtilityExitCodes.RestartCompleted;
                        }
                        else
                        {
                            ServiceEventSource.Current.ErrorMessage(
                                String.Format("Post restart, update of Repair task failed with {0}", resultState));
                            resultState = NodeAgentSfUtilityExitCodes.RetryableException;
                        }
                    }
                }

                break;
            }

            case RepairTaskState.Completed:
            case RepairTaskState.Restoring:
            {
                resultState = NodeAgentSfUtilityExitCodes.OperationCompleted;
                break;
            }

            default:
            {
                ServiceEventSource.Current.ErrorMessage(String.Format("Repair task for current node in unexpected state {0}", repairTask.State));
                resultState = NodeAgentSfUtilityExitCodes.RepairTaskInvalidState;
                break;
            }
            }

            ServiceEventSource.Current.InfoMessage("GetWuOperationStateAsync returned {0}", resultState);
            return(resultState);
        }