Example #1
0
// backup the app data.
// This method won't lock the taskMutex. You have to handle it!
func (a *App) backup() error {
	// Don't backup during some special app tasks.
	if a.task == taskCloneSource ||
		a.task == taskUpdate {
		return fmt.Errorf("can't backup app '%s' during an update task!", a.name)
	}

	// Get the app's base backup folder.
	backupPath := a.BackupDirectoryPath()

	// Create the base app backup folder if not present.
	err := utils.MkDirIfNotExists(backupPath)
	if err != nil {
		return fmt.Errorf("failed to backup app '%s': %v", a.name, err)
	}

	// Create a new backup directory with the current timestamp.
	backupPath += "/" + strconv.FormatInt(time.Now().Unix(), 10)

	// Log
	log.Infof("creating backup of app '%s': %s", a.name, backupPath)

	// Create a snapshot of the complete app subvolume.
	err = btrfs.Snapshot(a.path, backupPath, true)
	if err != nil {
		return fmt.Errorf("failed to backup app '%s': %v", a.name, err)
	}

	return nil
}
Example #2
0
// RestoreBackup restores the given app backup.
func (a *App) RestoreBackup(timestamp string) (err error) {
	// Lock the task mutex.
	// The app should not be started during a backup process.
	a.taskMutex.Lock()
	defer a.taskMutex.Unlock()

	// Abort if any app ask is running.
	if a.IsTaskRunning() {
		return fmt.Errorf("the app is running!")
	}

	// Create the backup directory path.
	backupPath := a.BackupDirectoryPath() + "/" + timestamp

	// Check if the backup exists.
	if !btrfs.IsSubvolume(backupPath) {
		return fmt.Errorf("no backup '%s' found!", timestamp)
	}

	// Create the apps backup path for the current data.
	newAppBackupPath := a.BackupDirectoryPath() + "/" + strconv.FormatInt(time.Now().Unix(), 10)

	// Log
	log.Infof("restoring backup of app '%s': %s", a.name, timestamp)

	// Reload the turtlefile and settings on defer.
	defer func() {
		err = a.reload()
	}()

	// Move the current subvolume to the backup location with the current timestamp.
	err = os.Rename(a.path, newAppBackupPath)
	if err != nil {
		return fmt.Errorf("failed to move apps current subvolume: %v", err)
	}

	// Restore the current backup subvolume on failure.
	defer func() {
		if err != nil {
			errR := os.Rename(newAppBackupPath, a.path)
			if errR != nil {
				log.Errorf("failed to restore apps current subvolume backup: %v", errR)
			} else {
				// Remove the readonly flag again.
				errR = btrfs.SetSubvolumeReadonly(a.path, false)
				if errR != nil {
					log.Errorf("failed to restore apps subvolume flag: %v", errR)
				}
			}
		}
	}()

	// Set the readonly flag on the moved subvolume.
	err = btrfs.SetSubvolumeReadonly(newAppBackupPath, true)
	if err != nil {
		return err
	}

	// Create a snapshot of the backup and restore it to the app path.
	err = btrfs.Snapshot(backupPath, a.path, false)
	if err != nil {
		return fmt.Errorf("failed to restore app '%s': %v", a.name, err)
	}

	return nil
}