From c0ad8cffb2c6acc672000efeabc9543ba8889bf5 Mon Sep 17 00:00:00 2001 From: Roman Vanicek Date: Sun, 5 May 2024 01:04:16 +0200 Subject: [PATCH] Backup snapshoting --- main.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 9e4c7cb..0b0df7f 100644 --- a/main.go +++ b/main.go @@ -35,11 +35,14 @@ import ( ) type ofsVolume struct { - Volume *volume.Volume - Fs string - Opts string - Env []string - Asap bool + Volume *volume.Volume + Fs string + Opts string + Env []string + Asap bool + // Create a snaphot on each mount (and delete the previous one) + Backup bool + BackupSnapshot string MountSnapshots bool SnapshotsFilter string } @@ -103,6 +106,8 @@ func (d *ofsDriver) Create(r *volume.CreateRequest) error { } case "asap": v.Asap = true + case "backup": + v.Backup = true case "mountSnapshots": v.MountSnapshots = val == "yes" case "snapshotsFilter": @@ -200,6 +205,15 @@ func umount(v *ofsVolume, rt *ofsVolumeRt) error { if err := os.Remove(v.Volume.Mountpoint); err != nil { return err } + + if v.Backup { + if err := applyEnv(exec.Command("/sbin/mount.objectivefs", "destroy", v.BackupSnapshot, "-f"), v.Env).Wait(); err == nil { + log.WithFields(log.Fields{"name": v.Volume.Name, "snapshot": v.BackupSnapshot}).Info("Failed to destroy the previous snapshot") + return err + } + v.BackupSnapshot = "" + } + rt.mounted = false return nil } @@ -276,17 +290,48 @@ func (d *ofsDriver) Mount(r *volume.MountRequest) (*volume.MountResponse, error) } log.WithFields(log.Fields{"name": r.Name, "id": r.ID}).Info("Attach ObjectiveFS Volume") + + // Each mount request causes new snapshot to get created and the old one deleted + if v.Backup && rt.mounted { + log.WithFields(log.Fields{"name": r.Name, "snapshot": v.BackupSnapshot}).Info("Going to unmount and destroy the previous backup snapshot") + if err := umount(v, rt); err != nil { + return &volume.MountResponse{}, err + } + } + if !rt.mounted { if err := os.MkdirAll(v.Volume.Mountpoint, 0755); err != nil { return &volume.MountResponse{}, err } + var fs string + if v.Backup { + log.WithFields(log.Fields{"name": r.Name}).Info("Going to create a backup snapshot") + if snapshotTextB, err := applyEnv(exec.Command("/sbin/mount.objectivefs", "snapshot", v.Fs), v.Env).CombinedOutput(); err == nil { + log.WithFields(log.Fields{"name": v.Volume.Name, "output": string(snapshotTextB[:])}).Info("Failed to create a new backup snapshot") + return &volume.MountResponse{}, err + } else { + // Format: NOTE: Successfully created snapshot: snapshotId () + const okPrefix = "NOTE: Successfully created snapshot:" + snapshotText := string(snapshotTextB[:]) + if snapshotIdWithSuffix, isOk := strings.CutPrefix(snapshotText, okPrefix); !isOk { + log.WithFields(log.Fields{"name": v.Volume.Name, "snapshot": v.BackupSnapshot}).Info("Failed to create a new backup snapshot") + return &volume.MountResponse{}, err + } else { + v.BackupSnapshot = strings.SplitAfter(snapshotIdWithSuffix, " ")[0] + fs = v.BackupSnapshot + } + } + } else { + fs = v.Fs + } + // Note: The first argument ("mount") causes running in the foreground, its absence in the background var cmd *exec.Cmd if len(v.Opts) == 0 { - cmd = exec.Command("/sbin/mount.objectivefs", "mount", v.Fs, v.Volume.Mountpoint) + cmd = exec.Command("/sbin/mount.objectivefs", "mount", fs, v.Volume.Mountpoint) } else { - cmd = exec.Command("/sbin/mount.objectivefs", "mount", "-o"+v.Opts, v.Fs, v.Volume.Mountpoint) + cmd = exec.Command("/sbin/mount.objectivefs", "mount", "-o"+v.Opts, fs, v.Volume.Mountpoint) } cmd.Env = v.Env