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 96b0940 commit 102bcb6
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
15 changes: 10 additions & 5 deletions pkg/plugin/restore_pvc_action_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@ package plugin
import (
"context"
"fmt"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/cmd"
"k8s.io/client-go/kubernetes"
"os"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"
backupdriverv1 "github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/apis/backupdriver/v1alpha1"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/backuprepository"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/cmd"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/constants"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
backupdriverTypedV1 "github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/generated/clientset/versioned/typed/backupdriver/v1alpha1"
pluginItem "github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/plugin/util"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/snapshotUtils"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/utils"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
"os"
)

// PVCBackupItemAction is a backup item action plugin for Velero.
Expand Down Expand Up @@ -201,6 +200,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
45 changes: 44 additions & 1 deletion pkg/plugin/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
backupdriverv1 "github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/apis/backupdriver/v1alpha1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/cmd"
"github.com/vmware-tanzu/velero-plugin-for-vsphere/pkg/constants"
"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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -226,6 +227,48 @@ 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 a associated with StorageClass with " +
"WaitForFirstConsumer VolumeBindingMode, this is currently not 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 102bcb6

Please sign in to comment.