protected override async Task <bool> OnDataLossAsync(RestoreContext restoreCtx, CancellationToken cancellationToken)
        {
            ServiceEventSource.Current.ServiceMessage(this.Context, "OnDataLoss Invoked!");
            this.SetupBackupManager();

            try
            {
                string backupFolder;

                backupFolder = await this.backupManager.RestoreLatestBackupToTempLocation(cancellationToken);

                ServiceEventSource.Current.ServiceMessage(this.Context, "Restoration Folder Path " + backupFolder);

                RestoreDescription restoreRescription = new RestoreDescription(backupFolder, RestorePolicy.Force);
                await restoreCtx.RestoreAsync(restoreRescription, cancellationToken);

                ServiceEventSource.Current.ServiceMessage(this.Context, "Restore completed");

                DirectoryInfo tempRestoreDirectory = new DirectoryInfo(backupFolder);
                tempRestoreDirectory.Delete(true);

                return(true);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceMessage(this.Context, "Restoration failed: " + "{0} {1}" + e.GetType() + e.Message);

                throw;
            }
        }
Exemple #2
0
        // OnDataLossAsync is the restore part of the process. This is NOT an arbitrary name, it is an override of the
        // method on StatefulServiceBase.
        // The method below looks in the backupFolder directory (where the backup files were
        // stored in BackupCallbackAsync above), searches for the folder of backup files that have the newest ListWriteTime, then restores them.
        // Once the RestoreDescription object is told where to find your data, RestoreAsync is called
        // to restore that data to the reliable objects
        // Each partition will have OnDataLossAsync called on it
        protected override async Task <bool> OnDataLossAsync(RestoreContext restoreCtx,
                                                             CancellationToken cancellationToken)
        {
            string backupFolder;

            ServiceEventSource.Current.ServiceMessage(this, "OnDataLoss Invoked!");

            this.SetupBackupManager();

            try
            {
                if (this.backupStorageType == BackupManagerType.None)
                {
                    //since we have no backup configured, we return false to indicate
                    //that state has not changed. This replica will become the basis
                    //for future replica builds
                    return(false);
                }
                else
                {
                    backupFolder =
                        await this.backupManager.RestoreLatestBackupToTempLocation(cancellationToken);
                }


                ServiceEventSource.Current.ServiceMessage(this, "Restoration Folder Path " + backupFolder);

                RestoreDescription restoreDescription =
                    new RestoreDescription(backupFolder, RestorePolicy.Force);

                // Restore the backup copy
                await restoreCtx.RestoreAsync(restoreDescription, cancellationToken);

                ServiceEventSource.Current.ServiceMessage(this, "Restore completed");

                // Clean up the local temporary directory (the root directory where all backups were unzipped in to)
                try
                {
                    DirectoryInfo tempRestoreDirectory = new DirectoryInfo(backupFolder);
                    tempRestoreDirectory.Delete(true);
                }
                catch (System.Exception ddel)
                {
                    ServiceEventSource.Current.ServiceMessage(this, "OnDataLossAsync: Delete of backup folder failed with {0}", ddel.Message);
                }

                // now that a restore has been performed, reset the full backup flag and incremental
                // counter so you start fresh again
                // You will need to change this type of logic for your own scenario
                takeFullBackup   = true;
                incrementalCount = 0;

                return(true);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceMessage(this, "Restoration failed: " + "{0} {1}" + e.GetType() + e.Message);
                throw;
            }
        }
        public async Task RestoreAsync(
            RestoreDescription restoreDescription,
            CancellationToken cancellationToken)
        {
            await this.restoreCtx.RestoreAsync(restoreDescription, cancellationToken);

            this.IsRestored       = true;
            this.BackupFolderPath = restoreDescription.BackupFolderPath;
            this.BackupPolicy     = restoreDescription.Policy;
        }
        public async Task Restore(IPersistentDownloader downloader, EventArgs eventArgs)
        {
            await m_init;

            if (eventArgs == EventArgs.Empty)
            {
                // !Note, we disable the event handler before we trigger an active restore, otherwise
                // the active restore event will notify the backup controller, while in fact the restore
                // command is issued from the controller, and SF backup manager should do it passively.
                Log.WriteLine($"{nameof(ServiceFabricBackupManager)}: initiating a new restore operation.");
                m_svc.RequestRestore -= OnServiceFabricRequestRestore;
                await m_svc.FabricClient.TestManager.StartPartitionDataLossAsync(Guid.NewGuid(), PartitionSelector.PartitionIdOf(m_svc.Context.ServiceName, m_svc.Context.PartitionId), DataLossMode.PartialDataLoss);

                await m_sem.WaitAsync();

                m_svc.RequestRestore += OnServiceFabricRequestRestore;
                return;
            }
            if (!(eventArgs is RestoreEventArgs rstArgs))
            {
                throw new NotSupportedException();
            }
            try
            {
                var ctx   = rstArgs.m_rctx;
                var dir   = Path.Combine(TrinityConfig.StorageRoot, Path.GetRandomFileName());
                var dsc   = new RestoreDescription(dir);
                var fname = Path.Combine(TrinityConfig.StorageRoot, Path.GetRandomFileName());
                using (var file = File.OpenWrite(fname))
                {
                    Log.WriteLine($"{nameof(ServiceFabricBackupManager)}: Downloading ServiceFabric backup data.");
                    await downloader.DownloadMetadataAsync(MetadataKey, file);
                }
                Log.WriteLine($"{nameof(ServiceFabricBackupManager)}: Decompressing ServiceFabric backup data.");
                FileUtility.CompletePath(dir, create_nonexistent: true);
                ZipFile.ExtractToDirectory(fname, dir);
                File.Delete(fname);
                Log.WriteLine($"{nameof(ServiceFabricBackupManager)}: Restoring ServiceFabric backup data.");
                await ctx.RestoreAsync(dsc);

                Directory.Delete(dir, recursive: true);
                Log.WriteLine($"{nameof(ServiceFabricBackupManager)}: Restored ServiceFabric backup data.");
                rstArgs.Complete();
            }
            catch (Exception ex)
            {
                rstArgs.Complete(ex);
                throw;
            }
            m_sem.Release();
        }
        //Dataloss testing can be triggered via powershell. To do so, run the following commands as a script
        //Connect-ServiceFabricCluster
        //$s = "fabric:/WebReferenceApplication/InventoryService"
        //$p = Get-ServiceFabricApplication | Get-ServiceFabricService -ServiceName $s | Get-ServiceFabricPartition | Select -First 1
        //$p | Invoke-ServiceFabricPartitionDataLoss -DataLossMode FullDataLoss -ServiceName $s

        protected override async Task <bool> OnDataLossAsync(RestoreContext restoreCtx, CancellationToken cancellationToken)
        {
            ServiceEventSource.Current.ServiceMessage(this, "OnDataLoss Invoked!");
            this.SetupBackupManager();

            try
            {
                string backupFolder;

                if (this.backupStorageType == BackupManagerType.None)
                {
                    //since we have no backup configured, we return false to indicate
                    //that state has not changed. This replica will become the basis
                    //for future replica builds
                    return(false);
                }
                else
                {
                    backupFolder = await this.backupManager.RestoreLatestBackupToTempLocation(cancellationToken);
                }

                ServiceEventSource.Current.ServiceMessage(this, "Restoration Folder Path " + backupFolder);

                RestoreDescription restoreRescription = new RestoreDescription(backupFolder, RestorePolicy.Force);

                await restoreCtx.RestoreAsync(restoreRescription, cancellationToken);

                ServiceEventSource.Current.ServiceMessage(this, "Restore completed");

                DirectoryInfo tempRestoreDirectory = new DirectoryInfo(backupFolder);
                tempRestoreDirectory.Delete(true);

                return(true);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceMessage(this, "Restoration failed: " + "{0} {1}" + e.GetType() + e.Message);

                throw;
            }
        }
        /// <summary>
        /// This method is called during suspected data loss.
        /// You can use this method to restore the service in case of data loss.
        /// </summary>
        /// <param name="service"></param>
        /// <param name="restoreCtx"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task <bool> OnDataLossAsync(this IBackupRestoreServiceInternal service, RestoreContext restoreCtx, CancellationToken cancellationToken)
        {
            //caused by BeginRestoreBackup
            service.LogCallback?.Invoke($"BackupRestoreService - OnDataLossAsync starting for partition: {service.Context.PartitionId}.");

            var metadata = await service.CentralBackupStore.RetrieveScheduledBackupAsync(service.Context.PartitionId);

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

            List <BackupMetadata> backupList = await GetBackupMetadataAsync(service, metadata);

            if (backupList.Count == 0)
            {
                throw new InvalidOperationException("Failed to find any backups for this partition.");
            }
            if (backupList[0].BackupOption != BackupOption.Full)
            {
                throw new InvalidOperationException("Failed to find any full backups for this partition.");
            }

            string localBackupFolder = Path.Combine(service.Context.CodePackageActivationContext.WorkDirectory, Guid.NewGuid().ToString("N"));

            foreach (var backupMetadata in backupList)
            {
                string subFolder = Path.Combine(localBackupFolder, backupMetadata.TimeStampUtc.ToString("yyyyMMddhhmmss"));
                await service.CentralBackupStore.DownloadBackupFolderAsync(backupMetadata.BackupId, subFolder, cancellationToken);
            }
            var restoreDescription = new RestoreDescription(localBackupFolder, RestorePolicy.Force);
            await restoreCtx.RestoreAsync(restoreDescription, cancellationToken);

            Directory.Delete(localBackupFolder, true);
            service.LogCallback?.Invoke($"BackupRestoreService - OnDataLossAsync complete for partition {service.Context.PartitionId}.");

            return(true);
        }
Exemple #7
0
        protected override async Task <bool> OnDataLossAsync(RestoreContext restoreCtx, CancellationToken cancellationToken)
        {
            this.SetupBackupManager();

            try
            {
                string backupFolder;
                backupFolder = await this.backupManager.RestoreLatestBackupToTempLocation(cancellationToken);

                RestoreDescription restoreRescription = new RestoreDescription(backupFolder, RestorePolicy.Force);

                await restoreCtx.RestoreAsync(restoreRescription, cancellationToken);

                DirectoryInfo tempRestoreDirectory = new DirectoryInfo(backupFolder);
                tempRestoreDirectory.Delete(true);

                return(true);
            }
            catch (Exception e)
            {
                throw;
            }
        }
 public Task RestoreAsync(
     RestoreDescription restoreDescription)
 {
     return(this.RestoreAsync(restoreDescription, CancellationToken.None));
 }
Exemple #9
0
        // OnDataLossAsync is the restore part of the process. This is NOT an arbitrary name, it is an override of the
        // method on StatefulServiceBase.
        // The method below looks in the c:\temp\sfbackup directory (where I stored the backup files in BackupCallbackAsync
        // above), searches for the folder of backup files that have the newest ListWriteTime, then restore them.
        // Once the RestoreDescription object is told where to find your data, RestoreAsync is called
        // to restore that data to the reliable objects
        protected override async Task <bool> OnDataLossAsync(RestoreContext restoreCtx,
                                                             CancellationToken cancellationToken)
        {
            ServiceEventSource.Current.ServiceMessage(this, "OnDataLoss Invoked!");
            this.SetupBackupManager();

            try
            {
                string restorePath = "";

                if (this.backupStorageType == BackupManagerType.None)
                {
                    //since we have no backup configured, we return false to indicate
                    //that state has not changed. This replica will become the basis
                    //for future replica builds
                    return(false);
                }
                else
                {
                    string zipPath = "";

                    string partitionId = this.Context.PartitionId.ToString("N");

                    //this will be the root directory for all unzipped files
                    ICodePackageActivationContext codePackageContext = this.Context.CodePackageActivationContext;
                    //this.PartitionTempDirectory = Path.Combine(codePackageContext.TempDirectory, partitionId);
                    this.PartitionTempDirectory = Path.Combine(@"C:\myrestore", partitionId);


                    // Get back the full list of blobs and do not sort them
                    // Sorting will be used when restoring a full-only backup
                    IEnumerable <IListBlobItem> blobs = await this.backupManager.GetBackupBlobs(false);

                    // the partition temp directory is the root restore directory + partitionId
                    // create this directory
                    System.IO.Directory.CreateDirectory(this.PartitionTempDirectory);


                    foreach (CloudBlockBlob backup in blobs)
                    {
                        // this is the full zip path including file name and extension
                        // this is the location the zip file should be downloaded to
                        zipPath = Path.Combine(this.PartitionTempDirectory, backup.Name);


                        // download the zip file from storage
                        try
                        {
                            // download the file in to the partition directory
                            backup.DownloadToFile(zipPath, FileMode.CreateNew);
                        }
                        catch (System.Exception ee)
                        {
                        }

                        string restoreDir = (backup.Name).Remove(backup.Name.Length - 4);

                        // Create a path in which to unzip the zip file that has been downloaded
                        // to the partiton directory
                        //restorePath = Path.Combine(this.PartitionTempDirectory, partitionId);
                        restorePath = Path.Combine(this.PartitionTempDirectory, restoreDir);

                        //extract the zip in to the local temp path directory
                        ZipFile.ExtractToDirectory(zipPath, restorePath);
                    }

                    //clean up the zip file, files are now in the restore path
                    FileInfo zipInfo = new FileInfo(zipPath);
                    zipInfo.Delete();

                    //backupFolder =
                    //    await this.backupManager.RestoreLatestBackupToTempLocationIncremental(cancellationToken);
                }

                ServiceEventSource.Current.ServiceMessage(this, "Restoration Folder Path " + restorePath);

                RestoreDescription restoreDescription =
                    new RestoreDescription(this.PartitionTempDirectory, RestorePolicy.Force);

                // Restore the backup copy
                await restoreCtx.RestoreAsync(restoreDescription, cancellationToken);

                ServiceEventSource.Current.ServiceMessage(this, "Restore completed");

                // Clean up the local temporary directory
                DirectoryInfo tempRestoreDirectory = new DirectoryInfo(this.PartitionTempDirectory);
                tempRestoreDirectory.Delete(true);

                return(true);
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceMessage(this, "Restoration failed: " + "{0} {1}" + e.GetType() + e.Message);

                throw;
            }
        }
        //Dataloss testing can be triggered via powershell. To do so, run the following commands as a script
        //Connect-ServiceFabricCluster
        //$s = "fabric:/WebReferenceApplication/InventoryService"
        //$p = Get-ServiceFabricApplication | Get-ServiceFabricService -ServiceName $s | Get-ServiceFabricPartition | Select -First 1
        //$p | Invoke-ServiceFabricPartitionDataLoss -DataLossMode FullDataLoss -ServiceName $s

        protected override async Task<bool> OnDataLossAsync(RestoreContext restoreCtx, CancellationToken cancellationToken)
        {
            ServiceEventSource.Current.ServiceMessage(this, "OnDataLoss Invoked!");
            this.SetupBackupManager();

            try
            {
                string backupFolder;

                if (this.backupStorageType == BackupManagerType.None)
                {
                    //since we have no backup configured, we return false to indicate
                    //that state has not changed. This replica will become the basis
                    //for future replica builds
                    return false;
                }
                else
                {
                    backupFolder = await this.backupManager.RestoreLatestBackupToTempLocation(cancellationToken);
                }

                ServiceEventSource.Current.ServiceMessage(this, "Restoration Folder Path " + backupFolder);

                RestoreDescription restoreRescription = new RestoreDescription(backupFolder, RestorePolicy.Force);

                await restoreCtx.RestoreAsync(restoreRescription, cancellationToken);

                ServiceEventSource.Current.ServiceMessage(this, "Restore completed");

                DirectoryInfo tempRestoreDirectory = new DirectoryInfo(backupFolder);
                tempRestoreDirectory.Delete(true);

                return true;
            }
            catch (Exception e)
            {
                ServiceEventSource.Current.ServiceMessage(this, "Restoration failed: " + "{0} {1}" + e.GetType() + e.Message);

                throw;
            }
        }
Exemple #11
0
        /// <summary>
        /// This method is called during suspected data loss.
        /// You can use this method to restore the service in case of data loss.
        /// </summary>
        /// <param name="service"></param>
        /// <param name="restoreCtx"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task <bool> OnDataLossAsync(this IBackupRestoreServiceOperations service, RestoreContext restoreCtx, CancellationToken cancellationToken)
        {
            //Ususally caused by BeginRestoreBackup

            //First, query the scheduled metadata for this partition backup
            service.LogCallback?.Invoke($"{nameof(BackupRestoreServiceOperations)} - {nameof(OnDataLossAsync)} - Starting for partition: {service.Context.PartitionId}.");
            BackupMetadata metadata;

            try
            {
                metadata = await service.CentralBackupStore.RetrieveScheduledBackupAsync(service.Context.PartitionId);
            }
            catch (Exception ex)
            {
                string message = $"Failed to find backup information for partition {service.Context.PartitionId}";
                service.LogCallback?.Invoke($"{nameof(BackupRestoreServiceOperations)} - {nameof(OnDataLossAsync)} - Failed for partition: {service.Context.PartitionId}. Message:{message} - Error: {ex.Message}");
                throw new Exception(message, ex);
            }

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

            //Get all metadata for all backups related to this one, if it's an incremental one
            List <BackupMetadata> backupList;

            try
            {
                backupList = await GetBackupMetadataAsync(service, metadata);

                if (backupList.Count < 1)
                {
                    throw new InvalidOperationException("Failed to find any backups for this partition.");
                }

                if (backupList[0].BackupOption != BackupOption.Full)
                {
                    throw new InvalidOperationException("Failed to find any full backups for this partition.");
                }
            }
            catch (Exception ex)
            {
                string message = $"Failed to find backup information for partition {service.Context.PartitionId}";
                service.LogCallback?.Invoke($"{nameof(BackupRestoreServiceOperations)} - {nameof(OnDataLossAsync)} - Failed for partition: {service.Context.PartitionId}. Message:{message} - Error: {ex.Message}");
                throw new Exception(message, ex);
            }

            //download central to local
            string localBackupFolder = Path.Combine(service.Context.CodePackageActivationContext.WorkDirectory, Guid.NewGuid().ToString("N"));

            try
            {
                foreach (var backupMetadata in backupList)
                {
                    string subFolder = Path.Combine(localBackupFolder, backupMetadata.TimeStampUtc.ToString("yyyyMMddhhmmss"));
                    await service.CentralBackupStore.DownloadBackupFolderAsync(backupMetadata.BackupId, subFolder, cancellationToken);
                }
            }
            catch (Exception ex)
            {
                string message = $"Failed to download backup data for partition {service.Context.PartitionId}";
                service.LogCallback?.Invoke($"{nameof(BackupRestoreServiceOperations)} - {nameof(OnDataLossAsync)} - Failed for partition: {service.Context.PartitionId}. Message:{message} - Error: {ex.Message}");
                throw new Exception(message, ex);
            }

            //restore
            try
            {
                var restoreDescription = new RestoreDescription(localBackupFolder, RestorePolicy.Force);
                await restoreCtx.RestoreAsync(restoreDescription, cancellationToken);
            }
            catch (Exception ex)
            {
                string message = $"Failed to restore backup for partition {service.Context.PartitionId}";
                service.LogCallback?.Invoke($"{nameof(BackupRestoreServiceOperations)} - {nameof(OnDataLossAsync)} - Failed for partition: {service.Context.PartitionId}. Message:{message} - Error: {ex.Message}");
                throw new Exception(message, ex);
            }
            finally
            {
                Directory.Delete(localBackupFolder, true);
            }

            //success!!
            service.LogCallback?.Invoke($"BackupRestoreService - OnDataLossAsync complete for partition {service.Context.PartitionId}.");

            return(true);
        }