Skip to content

Commit d14ecda

Browse files
committed
feat: restore cloud snapshot
Signed-off-by: Shivanjan Chakravorty <schakravorty@purestorage.com>
1 parent d745e02 commit d14ecda

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

csi/controller.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package csi
1818

1919
import (
2020
"encoding/json"
21+
"errors"
2122
"fmt"
2223
"math"
2324
"reflect"
@@ -477,6 +478,11 @@ func (s *OsdCsiServer) CreateVolume(
477478
return nil, status.Error(codes.InvalidArgument, "Name must be provided")
478479
}
479480

481+
if req.VolumeContentSource != nil && req.VolumeContentSource.GetSnapshot() != nil {
482+
clogger.WithContext(ctx).Infof("csi.CreateVolume restoring snapshot to Volume: %s", req.GetName())
483+
return s.restoreSnapshot(ctx, req)
484+
}
485+
480486
// Get parameters
481487
spec, locator, source, err := s.specHandler.SpecFromOpts(req.GetParameters())
482488
if err != nil {
@@ -632,6 +638,88 @@ func (s *OsdCsiServer) CreateVolume(
632638
}, nil
633639
}
634640

641+
func (s *OsdCsiServer) restoreSnapshot(ctx context.Context,
642+
req *csi.CreateVolumeRequest,
643+
) (resp *csi.CreateVolumeResponse, err error) {
644+
snapshot := req.VolumeContentSource.GetSnapshot()
645+
if snapshot == nil {
646+
return nil, errors.New("snapshot fetched is not accurate or does not exist")
647+
}
648+
649+
cloudBackupClient, err := s.getCloudBackupClient(ctx)
650+
cloudBackupClientAvailable := cloudBackupClient != nil
651+
cloudBackupDriverDisabled := sdk.IsErrorUnavailable(err)
652+
if (err != nil && !cloudBackupDriverDisabled) || cloudBackupClient == nil {
653+
return nil, err
654+
}
655+
656+
csiSnapshotID := snapshot.GetSnapshotId()
657+
if len(csiSnapshotID) == 0 {
658+
return nil, status.Error(codes.InvalidArgument, "Snapshot id must be provided")
659+
}
660+
661+
var backupStatus *api.SdkCloudBackupStatusResponse
662+
if cloudBackupClientAvailable && !cloudBackupDriverDisabled {
663+
// Check if snapshot has been created but is in error state
664+
backupStatus, err = cloudBackupClient.Status(ctx, &api.SdkCloudBackupStatusRequest{
665+
TaskId: csiSnapshotID,
666+
})
667+
}
668+
669+
isSnapshotIDPresentInCloud := true
670+
if backupStatus != nil {
671+
_, isSnapshotIDPresentInCloud = backupStatus.Statuses[csiSnapshotID]
672+
}
673+
674+
if (sdk.IsErrorNotFound(err) && !cloudBackupDriverDisabled && cloudBackupClientAvailable) || !isSnapshotIDPresentInCloud {
675+
676+
return
677+
}
678+
679+
resp, err = s.restoreCloudSnapshot(ctx, req)
680+
return
681+
682+
}
683+
684+
func (s *OsdCsiServer) restoreCloudSnapshot(ctx context.Context,
685+
req *csi.CreateVolumeRequest,
686+
) (resp *csi.CreateVolumeResponse, err error) {
687+
cloudBackupClient, err := s.getCloudBackupClient(ctx)
688+
if err != nil {
689+
return nil, err
690+
}
691+
// Get parameters
692+
_, locator, _, err := s.specHandler.SpecFromOpts(req.GetParameters())
693+
if err != nil {
694+
e := fmt.Sprintf("Unable to get parameters: %s\n", err.Error())
695+
clogger.WithContext(ctx).Errorln(e)
696+
return nil, status.Error(codes.InvalidArgument, e)
697+
}
698+
699+
csiSnapshotID := req.VolumeContentSource.GetSnapshot().GetSnapshotId()
700+
701+
credentialID := locator.VolumeLabels[osdSnapshotCredentialIDKey]
702+
703+
snapResp, err := cloudBackupClient.Restore(ctx, &api.SdkCloudBackupRestoreRequest{
704+
BackupId: csiSnapshotID,
705+
RestoreVolumeName: req.GetName(),
706+
TaskId: req.GetName(),
707+
Locator: locator,
708+
CredentialId: credentialID,
709+
})
710+
if nil != err {
711+
return nil, err
712+
}
713+
714+
resp = &csi.CreateVolumeResponse{
715+
Volume: &csi.Volume{
716+
VolumeId: snapResp.GetRestoreVolumeId(),
717+
ContentSource: req.VolumeContentSource,
718+
},
719+
}
720+
return
721+
}
722+
635723
func getClonedPVCMetadata(locator *api.VolumeLocator) map[string]string {
636724
metadataLabels := map[string]string{}
637725
pvcName, ok := locator.VolumeLabels[intreePvcNameKey]

0 commit comments

Comments
 (0)