Skip to content

Commit

Permalink
feat: snapshot path to include src volume name/uuid
Browse files Browse the repository at this point in the history
  • Loading branch information
wozniakjan committed Mar 20, 2023
1 parent 6143f00 commit 826d2f3
Showing 1 changed file with 68 additions and 20 deletions.
88 changes: 68 additions & 20 deletions pkg/nfs/controllerserver.go
Expand Up @@ -18,6 +18,7 @@ package nfs

import (
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -71,10 +72,20 @@ type nfsSnapshot struct {
baseDir string
// Snapshot name.
uuid string
// Source volume.
src string
}

func (snap nfsSnapshot) archiveSubPath() string {
return snap.uuid
}

func (snap nfsSnapshot) archiveName() string {
return fmt.Sprintf("%v.tar.gz", snap.uuid)
return fmt.Sprintf("%v.tar.gz", snap.src)
}

func (snap nfsSnapshot) archivePath() string {
return filepath.Join(snap.archiveSubPath(), snap.archiveName())
}

// Ordering of elements in the CSI volume id.
Expand All @@ -92,14 +103,15 @@ const (
)

// Ordering of elements in the CSI snapshot id.
// ID is of the form {server}/{baseDir}/snapshots.
// ID is of the form {server}/{baseDir}/{snap_name}/{src_name}.
// Adding a new element should always go at the end
// before totalSnapIDElements
const (
idSnapServer = iota
idSnapBaseDir
idSnapUUID
idSnapArchive
idSnapArchivePath
idSnapArchiveName
totalIDSnapElements // Always last
)

Expand Down Expand Up @@ -309,6 +321,13 @@ func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
klog.Warningf("failed to unmount snapshot nfs server: %v", err)
}
}()
snapInternalVolPath := filepath.Join(getInternalVolumePath(cs.Driver.workingMountDir, snapVol), snapshot.archiveSubPath())
if err = os.MkdirAll(snapInternalVolPath, 0777); err != nil {
return nil, status.Errorf(codes.Internal, "failed to make subdirectory: %v", err)
}
if err := validateSnapshot(snapInternalVolPath, snapshot); err != nil {
return nil, err
}

if err = cs.internalMount(ctx, srcVol, nil, nil); err != nil {
return nil, status.Errorf(codes.Internal, "failed to mount src nfs server: %v", err)
Expand All @@ -320,7 +339,7 @@ func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
}()

srcPath := getInternalVolumePath(cs.Driver.workingMountDir, srcVol)
dstPath := filepath.Join(getInternalVolumePath(cs.Driver.workingMountDir, snapVol), snapshot.archiveName())
dstPath := filepath.Join(snapInternalVolPath, snapshot.archiveName())
klog.V(2).Infof("archiving %v -> %v", srcPath, dstPath)
out, err := exec.Command("tar", "-C", srcPath, "-czvf", dstPath, ".").CombinedOutput()
if err != nil {
Expand Down Expand Up @@ -380,7 +399,7 @@ func (cs *ControllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS
}()

// delete snapshot archive
internalVolumePath := filepath.Join(getInternalVolumePath(cs.Driver.workingMountDir, vol), snap.archiveName())
internalVolumePath := filepath.Join(getInternalVolumePath(cs.Driver.workingMountDir, vol), snap.archiveSubPath())
klog.V(2).Infof("Removing snapshot archive at %v", internalVolumePath)
if err = os.RemoveAll(internalVolumePath); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error())
Expand All @@ -397,17 +416,6 @@ func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi
return nil, status.Error(codes.Unimplemented, "")
}

// Volume for snapshot internal mount/unmount
func volumeFromSnapshot(snap *nfsSnapshot) *nfsVolume {
return &nfsVolume{
id: snap.id,
server: snap.server,
baseDir: snap.baseDir,
subDir: snap.baseDir,
uuid: snap.uuid,
}
}

// Mount nfs server at base-dir
func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, volumeContext map[string]string, volCap *csi.VolumeCapability) error {
if volCap == nil {
Expand Down Expand Up @@ -485,7 +493,7 @@ func (cs *ControllerServer) copyFromSnapshot(ctx context.Context, req *csi.Creat
}()

// untar snapshot archive to dst path
snapPath := filepath.Join(getInternalVolumePath(cs.Driver.workingMountDir, snapVol), snap.archiveName())
snapPath := filepath.Join(getInternalVolumePath(cs.Driver.workingMountDir, snapVol), snap.archivePath())
dstPath := getInternalVolumePath(cs.Driver.workingMountDir, dstVol)
klog.V(2).Infof("copy volume from snapshot %v -> %v", snapPath, dstPath)
out, err := exec.Command("tar", "-xzvf", snapPath, "-C", dstPath).CombinedOutput()
Expand Down Expand Up @@ -568,6 +576,15 @@ func newNFSSnapshot(name string, params map[string]string, vol *nfsVolume) (*nfs
baseDir: baseDir,
uuid: name,
}
if vol.uuid != "" {
snapshot.src = vol.uuid
}
if vol.subDir != "" {
snapshot.src = vol.subDir
}
if snapshot.src == "" {
return nil, fmt.Errorf("missing required source volume name")
}
snapshot.id = getSnapshotIDFromNfsSnapshot(snapshot)
return snapshot, nil
}
Expand Down Expand Up @@ -656,7 +673,8 @@ func getSnapshotIDFromNfsSnapshot(snap *nfsSnapshot) string {
idElements[idSnapServer] = strings.Trim(snap.server, "/")
idElements[idSnapBaseDir] = strings.Trim(snap.baseDir, "/")
idElements[idSnapUUID] = snap.uuid
idElements[idSnapArchive] = snap.archiveName()
idElements[idSnapArchivePath] = snap.uuid
idElements[idSnapArchiveName] = snap.src
return strings.Join(idElements, separator)
}

Expand Down Expand Up @@ -702,14 +720,15 @@ func getNfsVolFromID(id string) (*nfsVolume, error) {
// Given a CSI snapshot ID, return a nfsSnapshot
// sample snapshot ID:
//
// nfs-server.default.svc.cluster.local#share#snapshot-016f784f-56f4-44d1-9041-5f59e82dbce1#snapshot-016f784f-56f4-44d1-9041-5f59e82dbce1.tar.gz
// nfs-server.default.svc.cluster.local#share#snapshot-016f784f-56f4-44d1-9041-5f59e82dbce1#snapshot-016f784f-56f4-44d1-9041-5f59e82dbce1#pvc-4bcbf944-b6f7-4bd0-b50f-3c3dd00efc64
func getNfsSnapFromID(id string) (*nfsSnapshot, error) {
segments := strings.Split(id, separator)
if len(segments) == 4 {
if len(segments) == totalIDSnapElements {
return &nfsSnapshot{
id: id,
server: segments[idSnapServer],
baseDir: segments[idSnapBaseDir],
src: segments[idSnapArchiveName],
uuid: segments[idSnapUUID],
}, nil
}
Expand All @@ -729,3 +748,32 @@ func isValidVolumeCapabilities(volCaps []*csi.VolumeCapability) error {
}
return nil
}

// Validate snapshot after internal mount
func validateSnapshot(snapInternalVolPath string, snap *nfsSnapshot) error {
return filepath.WalkDir(snapInternalVolPath, func(path string, d fs.DirEntry, err error) error {
if path == snapInternalVolPath {
// skip root
return nil
}
if err != nil {
return err
}
if d.Name() != snap.archiveName() {
// there should be just one archive in the snapshot path and archive name should match
return status.Errorf(codes.AlreadyExists, "snapshot with the same name but different source volume ID already exists: found %q, desired %q", d.Name(), snap.archiveName())
}
return nil
})
}

// Volume for snapshot internal mount/unmount
func volumeFromSnapshot(snap *nfsSnapshot) *nfsVolume {
return &nfsVolume{
id: snap.id,
server: snap.server,
baseDir: snap.baseDir,
subDir: snap.baseDir,
uuid: snap.uuid,
}
}

0 comments on commit 826d2f3

Please sign in to comment.