Skip to content

Commit

Permalink
Fail the Restore if the StorageClass is associated with WaitForFirstC…
Browse files Browse the repository at this point in the history
…onsumer volumeBindingMode

Signed-off-by: Deepak Kinni <[email protected]>
  • Loading branch information
Deepak Kinni committed Feb 29, 2024
1 parent 58768bb commit 3cbafd3
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
6 changes: 6 additions & 0 deletions pkg/plugin/restore_pvc_action_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ func (p *NewPVCRestoreItemAction) Execute(input *velero.RestoreItemActionExecute
}
}

// Check the StorageClass to validate that volumeBindingMode is not WaitForFirstConsumer
if err = pluginItem.ValidateRestoreStorageClass(restConfig, &itemSnapshot, p.Log); err != nil {
p.Log.Errorf("Failed to validate restore StorageClass VolumeBindingMode")
return nil, errors.WithStack(err)
}

snapshotID := itemSnapshot.Status.SnapshotID
snapshotMetadata := itemSnapshot.Status.Metadata
apiGroup := itemSnapshot.Spec.APIGroup
Expand Down
44 changes: 44 additions & 0 deletions pkg/plugin/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/utils"
"github.com/vmware-tanzu/velero/pkg/podvolume"
corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
Expand Down Expand Up @@ -227,6 +228,49 @@ func RetrieveStorageClassMapping(config *rest.Config, veleroNs string, logger lo
return configMaps.Items[0].Data, nil
}

func ValidateRestoreStorageClass(config *rest.Config, itemSnapshot *backupdriverv1.Snapshot, logger logrus.FieldLogger) error {
if itemSnapshot == nil {
return errors.New("itemSnapshot is nil, unable to retrieve the StorageClass for validation")
}

var err error
snapshotMetadata := itemSnapshot.Status.Metadata

pvc := &corev1.PersistentVolumeClaim{}
if err = pvc.Unmarshal(snapshotMetadata); err != nil {
logger.WithError(err).Error("Failed to unmarshal snapshotMetadata when validating StorageClass")
return err
}

if pvc.Spec.StorageClassName == nil || *pvc.Spec.StorageClassName == "" {
errMsg := fmt.Sprintf("PVC %s/%s has no storage class, unable to validate StorageClass",
pvc.Namespace, pvc.Name)
logger.Error(errMsg)
return errors.New(errMsg)
}

restoreStorageClassName := *pvc.Spec.StorageClassName
// validate that new storage class exists
clientset, err := GetKubeClient(config, logger)
if err != nil {
logger.Error("Failed to get core v1 client from given config")
return err
}
restoreStorageClass, err := clientset.StorageV1().StorageClasses().Get(context.TODO(), restoreStorageClassName, metav1.GetOptions{})
if err != nil {
return errors.Wrapf(err, "error getting storage class %s for validation",
restoreStorageClassName)
}
if restoreStorageClass.VolumeBindingMode != nil && *restoreStorageClass.VolumeBindingMode == storagev1.VolumeBindingWaitForFirstConsumer {
errMsg := fmt.Sprintf("The PVC to be restored is associated with StorageClass with " +
"WaitForFirstConsumer VolumeBindingMode, this is currently not supported. " +
"Only StorageClass with Immediate VolumeBindingMode is supported.")
logger.Error(errMsg)
return errors.New(errMsg)
}
return nil
}

func UpdateSnapshotWithNewStorageClass(config *rest.Config, itemSnapshot *backupdriverv1.Snapshot, storageClassMapping map[string]string, logger logrus.FieldLogger) (backupdriverv1.Snapshot, error) {
if itemSnapshot == nil {
return backupdriverv1.Snapshot{}, errors.New("itemSnapshot is nil, unable to update")
Expand Down

0 comments on commit 3cbafd3

Please sign in to comment.