예제 #1
0
        private void Execute(Models.Restore restore, LinkedList <CustomVersionedFile> files, bool isNewRestore)
        {
            // The `files` argument contains the filesystem paths and versions informed by the user for this restore.

            //
            // NOTE: The methods call ORDER is important!
            //

            SuppliedFiles = DoLoadOrCreateRestorePlanFiles(restore.RestorePlan, files);

            //throw new Exception("Simulating failure.");
        }
예제 #2
0
        public override void OnStart(CustomRestoreAgent agent, Models.Restore restore)
        {
            base.OnStart(agent, restore);

            _daoRestore.Insert(restore);

            var message = string.Format("Restore started at {0}", StartedAt);

            Info(message);
            //StatusInfo.Update(BackupStatusLevel.OK, message);

            OnUpdate(new RestoreOperationEvent {
                Status = RestoreOperationStatus.Started, Message = message
            });
        }
예제 #3
0
        public void OnFailure(CustomRestoreAgent agent, Models.Restore restore, Exception exception)
        {
            IsRunning = false;

            var message = string.Format("Restore failed: {0}", exception != null ? exception.Message : "Canceled?");

            Report.AddErrorMessage(message);
            Error(message);
            //StatusInfo.Update(RestoreStatusLevel.ERROR, message);

            restore.DidFail();
            _daoRestore.Update(restore);

            OnUpdate(new RestoreOperationEvent {
                Status = RestoreOperationStatus.Failed, Message = message
            });
        }
예제 #4
0
        private PathScanResults <CustomVersionedFile> DoWork(Models.Restore restore, CancellationToken cancellationToken)
        {
            // Scan files.
            DefaultRestoreScanner scanner = new DefaultRestoreScanner(restore.RestorePlan, cancellationToken);

#if DEBUG
            scanner.FileAdded += (object sender, CustomVersionedFile file) =>
            {
                logger.Debug("ADDED: File {0} @ {1}", file.Path, file.Version);
            };
            scanner.EntryScanFailed += (object sender, string path, string message, Exception ex) =>
            {
                logger.Debug("FAILED: {0} - Reason: {1}", path, message);
            };
#endif

            scanner.Scan();

            return(scanner.Results);
        }
예제 #5
0
        public async Task <FileVersionerResults> DoRestore(Models.Restore restore, LinkedList <CustomVersionedFile> files, bool newRestore)
        {
            Assert.IsNotNull(restore);
            Assert.AreEqual(TransferStatus.RUNNING, restore.Status);
            Assert.IsNotNull(files);

            Results.Reset();

            await ExecuteOnBackround(() =>
            {
                RestoreRepository daoRestore = new RestoreRepository();
                Restore = daoRestore.Get(restore.Id);

                RestorePlanFileRepository daoRestorePlanFile = new RestorePlanFileRepository();
                AllFilesFromPlan = daoRestorePlanFile.GetAllByPlan(restore.RestorePlan).ToDictionary <Models.RestorePlanFile, string>(p => p.Path);

                Execute(restore, files, newRestore);

                Save();
            }, CancellationToken);

            return(Results);
        }
예제 #6
0
        public virtual void OnStart(CustomRestoreAgent agent, Models.Restore restore)
        {
            IsRunning = true;

            restore.DidStart();
        }
예제 #7
0
        protected async void DoRestore(CustomRestoreAgent agent, Models.Restore restore, RestoreOperationOptions options)
        {
            try
            {
                CurrentState = RestoreOperationState.STARTING;
                OnStart(agent, restore);

                // Mount all network mappings and abort if there is any network mapping failure.
                CurrentState = RestoreOperationState.MAPPING_NETWORK_DRIVES;
                Helper.MountAllNetworkDrives();

                // Execute pre-actions
                CurrentState = RestoreOperationState.EXECUTING_PRE_ACTIONS;
                Helper.ExecutePreActions();

                //
                // Scanning
                //

                CurrentState = RestoreOperationState.SCANNING_FILES;
                LinkedList <CustomVersionedFile> filesToProcess = null;
                {
                    Task <PathScanResults <CustomVersionedFile> > filesToProcessTask = GetFilesToProcess(restore);

                    {
                        var message = string.Format("Scanning files started.");
                        Info(message);
                        //StatusInfo.Update(BackupStatusLevel.INFO, message);
                        OnUpdate(new RestoreOperationEvent {
                            Status = RestoreOperationStatus.ScanningFilesStarted, Message = message
                        });
                    }

                    try
                    {
                        await filesToProcessTask;
                    }
                    catch (Exception ex)
                    {
                        if (ex.IsCancellation())
                        {
                            string message = string.Format("Scanning files was canceled.");

                            Report.AddErrorMessage(message);
                            logger.Warn(message);
                        }
                        else
                        {
                            string message = string.Format("Caught exception during scanning files: {0}", ex.Message);

                            Report.AddErrorMessage(message);
                            logger.Log(LogLevel.Error, ex, message);
                        }

                        if (filesToProcessTask.IsFaulted || filesToProcessTask.IsCanceled)
                        {
                            if (filesToProcessTask.IsCanceled)
                            {
                                OnCancelation(agent, restore, ex);                                 // filesToProcessTask.Exception
                            }
                            else
                            {
                                OnFailure(agent, restore, ex);                                 // filesToProcessTask.Exception
                            }
                            return;
                        }
                    }

                    filesToProcess = filesToProcessTask.Result.Files;

                    {
                        foreach (var entry in filesToProcessTask.Result.FailedFiles)
                        {
                            Report.AddErrorMessage(entry.Value);
                        }

                        if (filesToProcessTask.Result.FailedFiles.Count > 0)
                        {
                            StringBuilder sb = new StringBuilder();
                            sb.AppendLine("Scanning failed for the following drives/files/directories:");
                            foreach (var entry in filesToProcessTask.Result.FailedFiles)
                            {
                                sb.AppendLine(string.Format("  Path: {0} - Reason: {1}", entry.Key, entry.Value));
                            }
                            Warn(sb.ToString());
                        }

                        var message = string.Format("Scanning files finished.");
                        Info(message);
                        //StatusInfo.Update(BackupStatusLevel.INFO, message);
                        OnUpdate(new RestoreOperationEvent {
                            Status = RestoreOperationStatus.ScanningFilesFinished, Message = message
                        });
                    }
                }

                //
                // Versioning
                //

                CurrentState = RestoreOperationState.VERSIONING_FILES;
                {
                    Task versionerTask = DoVersionFiles(restore, filesToProcess);

                    {
                        var message = string.Format("Processing files started.");
                        Info(message);
                        //StatusInfo.Update(RestoreStatusLevel.INFO, message);
                        OnUpdate(new RestoreOperationEvent {
                            Status = RestoreOperationStatus.ProcessingFilesStarted, Message = message
                        });
                    }

                    try
                    {
                        await versionerTask;
                    }
                    catch (Exception ex)
                    {
                        if (ex.IsCancellation())
                        {
                            string message = string.Format("Processing files was canceled.");

                            Report.AddErrorMessage(message);
                            logger.Warn(message);
                        }
                        else
                        {
                            string message = string.Format("Caught exception during processing files: {0}", ex.Message);

                            Report.AddErrorMessage(message);
                            logger.Log(LogLevel.Error, ex, message);
                        }

                        if (versionerTask.IsFaulted || versionerTask.IsCanceled)
                        {
                            Versioner.Undo();
                            if (versionerTask.IsCanceled)
                            {
                                OnCancelation(agent, restore, ex);                                 // versionerTask.Exception
                            }
                            else
                            {
                                OnFailure(agent, restore, ex);                                 // versionerTask.Exception
                            }
                            return;
                        }
                    }

                    agent.Files = Versioner.FilesToTransfer;

                    {
                        var message = string.Format("Processing files finished.");
                        Info(message);
                        //StatusInfo.Update(BackupStatusLevel.INFO, message);
                        OnUpdate(new RestoreOperationEvent {
                            Status = RestoreOperationStatus.ProcessingFilesFinished, Message = message
                        });
                    }

                    {
                        agent.Results.Stats.BytesTotal = agent.EstimatedTransferSize;

                        var message = string.Format("Estimated restore size: {0} files, {1}",
                                                    agent.Files.Count(), FileSizeUtils.FileSizeToString(agent.EstimatedTransferSize));
                        Info(message);
                    }
                }

                //
                // Transfer files
                //

                CurrentState = RestoreOperationState.TRANSFERRING_FILES;
                {
                    Task <TransferResults> transferTask = agent.Start();
                    Report.TransferResults = transferTask.Result;

                    {
                        var message = string.Format("Transfer files started.");
                        Info(message);
                    }

                    try
                    {
                        await transferTask;
                    }
                    catch (Exception ex)
                    {
                        if (ex.IsCancellation())
                        {
                            string message = string.Format("Transfer files was canceled.");

                            Report.AddErrorMessage(message);
                            logger.Warn(message);
                        }
                        else
                        {
                            string message = string.Format("Caught exception during transfer files: {0}", ex.Message);

                            Report.AddErrorMessage(message);
                            logger.Log(LogLevel.Error, ex, message);
                        }

                        if (transferTask.IsFaulted || transferTask.IsCanceled)
                        {
                            if (transferTask.IsCanceled)
                            {
                                OnCancelation(agent, restore, ex);                                 // transferTask.Exception
                            }
                            else
                            {
                                OnFailure(agent, restore, ex);                                 // transferTask.Exception
                            }
                            return;
                        }
                    }

                    {
                        var message = string.Format("Transfer files finished.");
                        Info(message);
                    }
                }

                CurrentState = RestoreOperationState.EXECUTING_POST_ACTIONS;
                Helper.ExecutePostActions(Report.TransferResults);

                CurrentState = RestoreOperationState.FINISHING;
                OnFinish(agent, restore);
            }
            catch (Exception ex)
            {
                OnFinish(agent, restore, ex);
            }
        }
예제 #8
0
 protected abstract Task DoVersionFiles(Models.Restore restore, LinkedList <CustomVersionedFile> files);
예제 #9
0
 protected abstract Task <PathScanResults <CustomVersionedFile> > GetFilesToProcess(Models.Restore restore);
예제 #10
0
        protected void RegisterResultsEventHandlers(Models.Restore restore, TransferResults results)
        {
            RestoredFileRepository daoRestoredFile = new RestoredFileRepository();
            BackupedFileRepository daoBackupedFile = new BackupedFileRepository();

            results.Failed += (object sender, TransferFileProgressArgs args) =>
            {
                Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath);
                restoredFile.TransferStatus = TransferStatus.FAILED;
                restoredFile.UpdatedAt      = DateTime.UtcNow;
                daoRestoredFile.Update(restoredFile);

                var message = string.Format("Failed {0} - {1}", args.FilePath, args.Exception != null ? args.Exception.Message : "Unknown reason");
                Warn(message);
                //StatusInfo.Update(BackupStatusLevel.ERROR, message);
                OnUpdate(new RestoreOperationEvent {
                    Status = RestoreOperationStatus.Updated, Message = message, TransferStatus = TransferStatus.FAILED
                });
            };
            results.Canceled += (object sender, TransferFileProgressArgs args) =>
            {
                Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath);
                restoredFile.TransferStatus = TransferStatus.CANCELED;
                restoredFile.UpdatedAt      = DateTime.UtcNow;
                daoRestoredFile.Update(restoredFile);

                var message = string.Format("Canceled {0} - {1}", args.FilePath, args.Exception != null ? args.Exception.Message : "Unknown reason");
                Warn(message);
                //StatusInfo.Update(BackupStatusLevel.ERROR, message);
                OnUpdate(new RestoreOperationEvent {
                    Status = RestoreOperationStatus.Updated, Message = message, TransferStatus = TransferStatus.CANCELED
                });
            };
            results.Completed += (object sender, TransferFileProgressArgs args) =>
            {
                Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath);
                restoredFile.TransferStatus = TransferStatus.COMPLETED;
                restoredFile.UpdatedAt      = DateTime.UtcNow;
                daoRestoredFile.Update(restoredFile);

                // Only set original modified date if the restored file is the latest version whose transfer is completed,
                // otherwise, keep the date the OS/filesystem gave it.
                bool isLatestVersion = daoBackupedFile.IsLatestVersion(restoredFile.BackupedFile);
                if (isLatestVersion)
                {
                    // Set original LastWriteTime so this file won't be erroneously included in the next Backup.
                    FileManager.SafeSetFileLastWriteTimeUtc(restoredFile.File.Path, restoredFile.BackupedFile.FileLastWrittenAt);
                }
                else
                {
                    // Keep the original LastWriteTime so this file will be included in the next backup.
                }

                var message = string.Format("Completed {0}", args.FilePath);
                Info(message);
                OnUpdate(new RestoreOperationEvent {
                    Status = RestoreOperationStatus.Updated, Message = message, TransferStatus = TransferStatus.COMPLETED
                });
            };
            results.Started += (object sender, TransferFileProgressArgs args) =>
            {
                Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath);
                restoredFile.TransferStatus = TransferStatus.RUNNING;
                restoredFile.UpdatedAt      = DateTime.UtcNow;
                daoRestoredFile.Update(restoredFile);

                var message = string.Format("Started {0}", args.FilePath);
                Info(message);
                OnUpdate(new RestoreOperationEvent {
                    Status = RestoreOperationStatus.Updated, Message = message
                });
            };
            results.Progress += (object sender, TransferFileProgressArgs args) =>
            {
#if DEBUG
                var message = string.Format("Progress {0}% {1} ({2}/{3} bytes)",
                                            args.PercentDone, args.FilePath, args.TransferredBytes, args.TotalBytes);
                //Info(message);
#endif
                OnUpdate(new RestoreOperationEvent {
                    Status = RestoreOperationStatus.Updated, Message = null
                });
            };
        }
예제 #11
0
 protected override Task DoVersionFiles(Models.Restore restore, LinkedList <CustomVersionedFile> files)
 {
     return(Versioner.NewRestore(restore, files));
 }
예제 #12
0
 protected override Task <PathScanResults <CustomVersionedFile> > GetFilesToProcess(Models.Restore restore)
 {
     return(ExecuteOnBackround(() =>
     {
         return DoWork(restore, CancellationTokenSource.Token);
     }, CancellationTokenSource.Token));
 }
예제 #13
0
 public NewRestoreOperation(Models.RestorePlan plan, RestoreOperationOptions options)
     : base(options)
 {
     Restore = new Models.Restore(plan);
 }
예제 #14
0
 public async Task <FileVersionerResults> ResumeRestore(Models.Restore restore, LinkedList <CustomVersionedFile> files)
 {
     return(await DoRestore(restore, files, false));
 }
예제 #15
0
 //
 // Summary:
 // ...
 //
 private IEnumerable <CustomVersionedFile> GetFilesToTransfer(Models.Restore restore, LinkedList <Models.RestorePlanFile> files)
 {
     return(files.Select(p => p.VersionedFile));
 }
예제 #16
0
        private void OnControlPlanQuery(object sender, ServerCommandEventArgs e)
        {
            string planType = e.Command.GetArgumentValue <string>("planType");
            Int32  planId   = e.Command.GetArgumentValue <Int32>("planId");

            ValidatePlanType(planType);

            bool isRunning   = IsPlanRunning(planType, planId);
            bool needsResume = false;
            bool isFinished  = false;

            bool isBackup  = planType.Equals(PlanTypeEnum.BACKUP.ToString().ToLowerInvariant());
            bool isRestore = planType.Equals(PlanTypeEnum.RESTORE.ToString().ToLowerInvariant());

            // Report to GUI.
            Commands.GuiReportPlanStatus report = new Commands.GuiReportPlanStatus();

            if (isBackup)
            {
                BackupRepository daoBackup = new BackupRepository();
                Models.Backup    latest    = daoBackup.GetLatestByPlan(new Models.BackupPlan {
                    Id = planId
                });

                needsResume = latest != null && latest.NeedsResume();
                isFinished  = latest != null && latest.IsFinished();

                if (isRunning)
                {
                    report.StartedAt = latest.StartedAt;
                }
                else if (isFinished)
                {
                    report.FinishedAt = latest.FinishedAt;
                }
            }
            else if (isRestore)
            {
                RestoreRepository daoRestore = new RestoreRepository();
                Models.Restore    latest     = daoRestore.GetLatestByPlan(new Models.RestorePlan {
                    Id = planId
                });

                needsResume = latest != null && latest.NeedsResume();
                isFinished  = latest != null && latest.IsFinished();

                if (isRunning)
                {
                    report.StartedAt = latest.StartedAt;
                }
                else if (isFinished)
                {
                    report.FinishedAt = latest.FinishedAt;
                }
            }

            bool isInterrupted = !isRunning && needsResume;

            Commands.OperationStatus status;
            // The condition order below is important because more than one flag might be true.
            if (isInterrupted)
            {
                status = Commands.OperationStatus.INTERRUPTED;
            }
            else if (needsResume)
            {
                status = Commands.OperationStatus.RESUMED;
            }
            else if (isRunning)
            {
                status = Commands.OperationStatus.STARTED;
            }
            else
            {
                status = Commands.OperationStatus.NOT_RUNNING;
            }

            report.Status = status;

            Handler.Send(e.Context, Commands.GuiReportOperationStatus(planType, planId, report));
        }