private NativeMethods.IUpdate GetUpdateToDownload(NativeMethods.IUpdateCollection updateCollection)
        {
            try
            {
                NativeMethods.IUpdate updateToDownload = null;
                if (updateCollection.Count > 0)
                {
                    foreach (NativeMethods.IUpdate update in updateCollection)
                    {
                        if (updateToDownload != null)
                        {
                            Trace.WriteWarning(TraceType, "GetUpdateToDownload: Update collection has more then one update: {0}", update.Identity.UpdateID);
                        }
                        else
                        {
                            updateToDownload = update;
                        }
                    }
                }

                // Taking the first one
                return(updateToDownload);
            }
            catch (Exception ex)
            {
                Trace.WriteError(TraceType, "GetUpdateToDownload: Error : {0}", ex);
            }

            return(null);
        }
        // Return true if upgrade started other wise false
        private async Task <bool> OnGettingUpdateCollectionAsync(
            NativeMethods.IUpdateCollection updateCollection,
            FabricUpgradeProgress upgradeProgress,
            CancellationToken token)
        {
            ClusterUpgradeCommandParameter commandParameter = null;
            string updateId = string.Empty;

            if (updateCollection != null)
            {
                NativeMethods.IUpdate updateToDownload = this.GetUpdateToDownload(updateCollection);
                if (updateToDownload != null)
                {
                    Trace.WriteInfo(TraceType, "OnGettingUpdateCollectionAsync: Update to download: {0}", updateToDownload.Identity.UpdateID);
                    commandParameter = await this.packageRetriever.DownloadWindowsUpdate(updateToDownload, this.windowsUpdateApiTimeout, token);

                    updateId = updateToDownload.Identity.UpdateID;
                }
                else
                {
                    Trace.WriteInfo(TraceType, "OnGettingUpdateCollectionAsync: No update found.");
                }
            }
            else
            {
                Trace.WriteInfo(TraceType, "OnGettingUpdateCollectionAsync: update collection is null.");
                if (this.testMode && Directory.Exists(this.testSrcDir))
                {
                    var srcCabFile = Directory.GetFiles(this.testSrcDir, "*.cab", SearchOption.TopDirectoryOnly).FirstOrDefault();
                    if (!string.IsNullOrWhiteSpace(srcCabFile))
                    {
                        Trace.WriteWarning(TraceType, "OnGettingUpdateCollectionAsync: Test cab file {0}", srcCabFile);
                        var dir  = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                        var info = new DirectoryInfo(dir);
                        if (!info.Exists)
                        {
                            info.Create();
                        }

                        updateId = Guid.NewGuid().ToString();
                        var destCabFile = Path.Combine(dir, "test.cab");
                        File.Copy(srcCabFile, destCabFile);
                        Trace.WriteWarning(TraceType, "OnGettingUpdateCollectionAsync: Test dest file {0}", destCabFile);
                        var cabVersion = CabFileOperations.GetCabVersion(destCabFile);
                        Trace.WriteWarning(TraceType, "OnGettingUpdateCollectionAsync: Cab version {0}", cabVersion);
                        commandParameter = new ClusterUpgradeCommandParameter()
                        {
                            CodeFilePath = destCabFile,
                            CodeVersion  = cabVersion
                        };
                    }
                }
            }

            if (commandParameter == null)
            {
                return(false);
            }

            var updatedCommandParameter = await this.UpdateReplicaStoreBeforeUpgradeStartAsync(
                commandParameter,
                upgradeProgress,
                updateId,
                token);

            var upgradeTask = await this.commandProcessor.ClusterUpgradeAsync(updatedCommandParameter, TimeSpan.MaxValue, token).ContinueWith(
                (task) =>
            {
                if (commandParameter != null)
                {
                    DeleteFileDirectory(commandParameter.CodeFilePath);
                    DeleteFileDirectory(commandParameter.ConfigFilePath);
                }

                return(task);
            });

            await upgradeTask;

            return(true);
        }
        // Returns the duration to wait before trying again..
        private async Task <TimeSpan> UpgradeWorkAsync(CancellationToken token)
        {
            Trace.WriteInfo(TraceType, "UpgradeWorkAsync: Get fabric upgrade progress");
            var upgradeProgress = await this.commandProcessor.GetFabricUpgradeProgressAsync(Constants.MaxOperationTimeout, token);

            var upgradeState = upgradeProgress.UpgradeState;

            if (upgradeProgress.TargetCodeVersion == "0.0.0.0")
            {
                return(await this.InitiateBaseUpgradeAsync(token));
            }
            else if (upgradeState == FabricUpgradeState.RollingBackCompleted || upgradeState == FabricUpgradeState.RollingForwardCompleted)
            {
                var  baseUpgrade     = this.configStore.ReadUnencryptedString(this.configSectionName, Constants.WUSCoordinator.OnlyBaseUpgradeParam);
                bool onlyBaseUpgrade = false;
                if (!bool.TryParse(baseUpgrade, out onlyBaseUpgrade))
                {
                    onlyBaseUpgrade = false;
                }

                if (onlyBaseUpgrade)
                {
                    Trace.WriteInfo(TraceType, "Only base upgrade");
                    return(this.waitTimeBeforePolling);
                }

                var waitDuration = await this.GetWaitDurationAndUpdateHealth(upgradeProgress, token);

                if (waitDuration != TimeSpan.MinValue && waitDuration.TotalMinutes > 0)
                {
                    return(waitDuration);
                }

                Trace.WriteInfo(TraceType, "UpgradeWorkAsync: Check for the next upgrade package");
                NativeMethods.IUpdateCollection updateCollections = null;
                if (!this.testMode)
                {
                    updateCollections = await this.packageRetriever.GetAvailableUpdates(this.windowsUpdateApiTimeout, token);
                }

                var upgradeStarted = await this.OnGettingUpdateCollectionAsync(updateCollections, upgradeProgress, token);

                if (upgradeStarted)
                {
                    return(TimeSpan.MinValue);
                }
            }
            else if (upgradeState == FabricUpgradeState.RollingBackInProgress ||
                     upgradeState == FabricUpgradeState.RollingForwardInProgress)
            {
                Trace.WriteInfo(
                    TraceType,
                    "UpgradeWorkAsync: upgrade to code version:{0} config version: {1} and state:{2} happening.",
                    upgradeProgress.TargetCodeVersion,
                    upgradeProgress.TargetConfigVersion,
                    upgradeProgress.UpgradeState);

                await this.UpdateReplicaStoreAfterUpgradeStartAsync(upgradeProgress, token);

                var lastUpgradeProgress = await this.commandProcessor.GetCurrentRunningUpgradeTaskAsync(TimeSpan.MaxValue, token);

                Trace.WriteInfo(TraceType,
                                "UpgradeWorkAsync: Upgrade completed state: {0}, Code version:{1}, Config version:{2}",
                                lastUpgradeProgress.UpgradeState,
                                lastUpgradeProgress.TargetCodeVersion,
                                lastUpgradeProgress.TargetConfigVersion);
                return(TimeSpan.MinValue);
            }
            else
            {
                Trace.WriteError(
                    TraceType,
                    "UpgradeWorkAsync: Invalid Current upgrade state '{0}'",
                    upgradeState);
            }

            return(this.waitTimeBeforePolling);
        }