Volume with mounted snaphosts cannot unmount.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-03-19 21:08:39 +01:00
parent 93040ab946
commit c831659a0e

110
main.go
View File

@@ -57,11 +57,6 @@ type ofsDriver struct {
defMountSnapshots bool
}
type snapshotRule struct {
count int
period time.Duration
}
var version = "1.0"
var objfsVersion = "7.2"
@@ -169,8 +164,27 @@ func (d *ofsDriver) Get(r *volume.GetRequest) (*volume.GetResponse, error) {
func umount(v *ofsVolume, rt *ofsVolumeRt) error {
log.WithFields(log.Fields{"name": v.Volume.Name}).Info("Unmount ObjectiveFS Volume")
if !rt.mounted {
return fmt.Errorf("Volume is not mounted")
return fmt.Errorf("volume is not mounted")
}
if v.MountSnapshots {
// Snapshots must be unmounted first
// Note: We do NOT remove the mount directory as other distributed mounts may be using them
snapshotsPath := path.Join(v.Volume.Mountpoint, snapshotsDirectory)
if existingMounts, err := getMountedSnaphots(snapshotsPath, true); err == nil {
log.WithFields(log.Fields{"name": v.Volume.Name, "existingMounts": existingMounts}).Trace("Existing snapshot mounts")
for i, path := range existingMounts {
if err := exec.Command("umount", path).Run(); err != nil {
log.WithFields(log.Fields{"name": v.Volume.Name, "snapshot": i}).Warn("Failed to unmount a snapshot on unmount.")
} else {
log.WithFields(log.Fields{"name": v.Volume.Name, "snapshot": i}).Trace("Snapshot unmounted on unmount.")
}
}
} else {
log.WithFields(log.Fields{"name": v.Volume.Name, "Error": err}).Warn("Cannot determine existing snapshot mounts on unmount")
}
}
if err := exec.Command("umount", v.Volume.Mountpoint).Run(); err != nil {
return err
}
@@ -330,44 +344,56 @@ func (d *ofsDriver) Mount(r *volume.MountRequest) (*volume.MountResponse, error)
if existingSnapshotsB, err := applyEnv(exec.Command("/sbin/mount.objectivefs", "list", "-sz", v.Fs), v.Env).Output(); err == nil {
if existingSnapshots, err := parseExistingSnapshots(string(existingSnapshotsB), v.Fs); err == nil {
log.WithFields(log.Fields{"name": r.Name, "existingSnapshots": existingSnapshots}).Trace("Existing snapshots")
if existingMounts, err := getMountedSnaphots(snapshotsPath); err == nil {
if existingMounts, err := getMountedSnaphots(snapshotsPath, true); err == nil {
log.WithFields(log.Fields{"name": r.Name, "existingMounts": existingMounts}).Trace("Existing snapshot mounts")
if existingMountDirs, err := getMountedSnaphots(snapshotsPath, false); err == nil {
log.WithFields(log.Fields{"name": r.Name, "existingMountDirs": existingMounts}).Trace("Existing snapshot mount dirs")
// Remove mounts of expired snapshots
for i, path := range setMinus(existingMounts, expectedSnapshots) {
if err := exec.Command("umount", path).Run(); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to unmount an expired snapshot.")
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Debug("Snapshot unmounted.")
}
if err := os.Remove(path); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to remove directory of an expired snapshot.")
}
}
// Destroy old snapshots
for i, name := range setMinus(existingSnapshots, expectedSnapshots) {
expectedOutput := "Snapshot '" + name + "' destroyed."
if output, err := applyEnv(exec.Command("/sbin/mount.objectivefs", "destroy", name, "-f"), v.Env).Output(); err != nil || strings.TrimSpace(string(output)) != expectedOutput {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to destroy an expired snapshot.")
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Debug("Snapshot destroyed.")
}
}
// Add new mounts
for i, name := range setMinus(setIntersect(existingSnapshots, expectedSnapshots), existingMounts) {
dest := filepath.Join(snapshotsPath, i)
if err := os.Mkdir(dest, os.ModePerm); err == nil || os.IsExist(err) {
// Note: There is a missing "mount" argument so the mount continues running in a background process
if err := applyEnv(exec.Command("/sbin/mount.objectivefs", name, dest), v.Env).Run(); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to mount a new snapshot.")
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Debug("Snapshot mounted.")
// Remove left-over dirs of expired snapshots (ie. appears during downtime)
for i, path := range setMinus(setMinus(existingMountDirs, expectedSnapshots), existingMounts) {
if err := os.Remove(path); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to remove directory of an off-line expired snapshot.")
}
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to create directory for a snapshot.")
}
// Remove mounts of expired snapshots
for i, path := range setMinus(existingMounts, expectedSnapshots) {
if err := exec.Command("umount", path).Run(); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to unmount an expired snapshot.")
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Debug("Snapshot unmounted.")
}
if err := os.Remove(path); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to remove directory of an expired snapshot.")
}
}
// Destroy old snapshots
for i, name := range setMinus(existingSnapshots, expectedSnapshots) {
expectedOutput := "Snapshot '" + name + "' destroyed."
if output, err := applyEnv(exec.Command("/sbin/mount.objectivefs", "destroy", name, "-f"), v.Env).Output(); err != nil || strings.TrimSpace(string(output)) != expectedOutput {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to destroy an expired snapshot.")
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Debug("Snapshot destroyed.")
}
}
// Add new mounts
for i, name := range setMinus(setIntersect(existingSnapshots, expectedSnapshots), existingMounts) {
dest := filepath.Join(snapshotsPath, i)
if err := os.Mkdir(dest, os.ModePerm); err == nil || os.IsExist(err) {
// Note: There is a missing "mount" argument so the mount continues running in a background process
if err := applyEnv(exec.Command("/sbin/mount.objectivefs", name, dest), v.Env).Run(); err != nil {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to mount a new snapshot.")
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Debug("Snapshot mounted.")
}
} else {
log.WithFields(log.Fields{"name": r.Name, "snapshot": i}).Warn("Failed to create directory for a snapshot.")
}
}
} else {
log.WithFields(log.Fields{"name": r.Name, "Error": err}).Warn("Cannot determine existing snapshot mount dirs")
}
} else {
log.WithFields(log.Fields{"name": r.Name, "Error": err}).Warn("Cannot determine existing snapshot mounts")
@@ -629,7 +655,7 @@ func parseExistingSnapshots(data string, expectedPrefix string) (map[string]stri
return result, nil
}
func getMountedSnaphots(baseDir string) (map[string]string, error) {
func getMountedSnaphots(baseDir string, checkMount bool) (map[string]string, error) {
if entries, err := os.ReadDir(baseDir); err != nil {
return nil, err
} else {
@@ -637,7 +663,7 @@ func getMountedSnaphots(baseDir string) (map[string]string, error) {
for _, i := range entries {
if i.IsDir() {
iPath := filepath.Join(baseDir, i.Name())
if isObjFs, err := isObjectiveFsMount(iPath); err == nil && isObjFs {
if isObjFs, err := isObjectiveFsMount(iPath); !checkMount || (err == nil && isObjFs) {
result[i.Name()] = iPath
}
}