Skip to content

Commit

Permalink
Merge CSI plugin code.
Browse files Browse the repository at this point in the history
Signed-off-by: Xun Jiang <[email protected]>
  • Loading branch information
blackpiglet committed Apr 3, 2024
1 parent d974cd3 commit 2001b16
Show file tree
Hide file tree
Showing 59 changed files with 5,358 additions and 102 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/7609-blackpiglet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Merge CSI plugin code into Velero.
75 changes: 75 additions & 0 deletions internal/delete/actions/csi_volumesnapshot_action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package actions

import (
"context"
"fmt"

snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/util/csi"
)

// csiVolumeSnapshotDeleteItemAction is a backup item action plugin for Velero.
type csiVolumeSnapshotDeleteItemAction struct {
Log logrus.FieldLogger
}

// AppliesTo returns information indicating that the VolumeSnapshotBackupItemAction should be invoked to backup volumesnapshots.
func (p *csiVolumeSnapshotDeleteItemAction) AppliesTo() (velero.ResourceSelector, error) {
p.Log.Debug("VolumeSnapshotBackupItemAction AppliesTo")

return velero.ResourceSelector{
IncludedResources: []string{"volumesnapshots.snapshot.storage.k8s.io"},
}, nil
}

func (p *csiVolumeSnapshotDeleteItemAction) Execute(input *velero.DeleteItemActionExecuteInput) error {
p.Log.Info("Starting VolumeSnapshotDeleteItemAction for volumeSnapshot")

var vs snapshotv1api.VolumeSnapshot

if err := runtime.DefaultUnstructuredConverter.FromUnstructured(input.Item.UnstructuredContent(), &vs); err != nil {
return errors.Wrapf(err, "failed to convert input.Item from unstructured")
}

// We don't want this DeleteItemAction plugin to delete Volumesnapshot taken outside of Velero.
// So skip deleting Volumesnapshot objects that were not created in the process of creating
// the Velero backup being deleted.
if !csi.HasBackupLabel(&vs.ObjectMeta, input.Backup.Name) {
p.Log.Info("VolumeSnapshot %s/%s was not taken by backup %s, skipping deletion", vs.Namespace, vs.Name, input.Backup.Name)
return nil
}

p.Log.Infof("Deleting Volumesnapshot %s/%s", vs.Namespace, vs.Name)
_, snapClient, err := csi.GetClients()
if err != nil {
return errors.WithStack(err)
}
if vs.Status != nil && vs.Status.BoundVolumeSnapshotContentName != nil {
// we patch the DeletionPolicy of the volumesnapshotcontent to set it to Delete.
// This ensures that the volume snapshot in the storage provider is also deleted.
err := csi.SetVolumeSnapshotContentDeletionPolicy(*vs.Status.BoundVolumeSnapshotContentName, snapClient.SnapshotV1())
if err != nil && !apierrors.IsNotFound(err) {
return errors.Wrapf(err, fmt.Sprintf("failed to patch DeletionPolicy of volume snapshot %s/%s", vs.Namespace, vs.Name))
}

if apierrors.IsNotFound(err) {
return nil
}
}
err = snapClient.SnapshotV1().VolumeSnapshots(vs.Namespace).Delete(context.TODO(), vs.Name, metav1.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}
return nil
}

func NewCsiVolumeSnapshotDeleteItemAction(logger logrus.FieldLogger) (interface{}, error) {
return &csiVolumeSnapshotDeleteItemAction{logger}, nil
}
81 changes: 81 additions & 0 deletions internal/delete/actions/csi_volumesnapshotcontent_action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package actions

import (
"context"
"fmt"

snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/util/csi"
)

// csiVolumeSnapshotContentDeleteItemAction is a restore item action plugin for Velero
type csiVolumeSnapshotContentDeleteItemAction struct {
Log logrus.FieldLogger
}

// AppliesTo returns information indicating VolumeSnapshotContentRestoreItemAction action should be invoked while restoring
// volumesnapshotcontent.snapshot.storage.k8s.io resources
func (p *csiVolumeSnapshotContentDeleteItemAction) AppliesTo() (velero.ResourceSelector, error) {
return velero.ResourceSelector{
IncludedResources: []string{"volumesnapshotcontent.snapshot.storage.k8s.io"},
}, nil
}

func (p *csiVolumeSnapshotContentDeleteItemAction) Execute(input *velero.DeleteItemActionExecuteInput) error {
p.Log.Info("Starting VolumeSnapshotContentDeleteItemAction")

var snapCont snapshotv1api.VolumeSnapshotContent
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(input.Item.UnstructuredContent(), &snapCont); err != nil {
return errors.Wrapf(err, "failed to convert input.Item from unstructured")
}

// We don't want this DeleteItemAction plugin to delete VolumesnapshotContent taken outside of Velero.
// So skip deleting VolumesnapshotContent objects that were not created in the process of creating
// the Velero backup being deleted.
if !csi.HasBackupLabel(&snapCont.ObjectMeta, input.Backup.Name) {
p.Log.Info("VolumeSnapshotContent %s was not taken by backup %s, skipping deletion", snapCont.Name, input.Backup.Name)
return nil
}

p.Log.Infof("Deleting VolumeSnapshotContent %s", snapCont.Name)

_, snapClient, err := csi.GetClients()
if err != nil {
return errors.WithStack(err)
}

err = csi.SetVolumeSnapshotContentDeletionPolicy(snapCont.Name, snapClient.SnapshotV1())
if err != nil {
// #4764: Leave a warning when VolumeSnapshotContent cannot be found for deletion.
// Manual deleting VolumeSnapshotContent can cause this.
// It's tricky for Velero to handle this inconsistency.
// Even if Velero restores the VolumeSnapshotContent, CSI snapshot controller
// may not delete it correctly due to the snapshot represented by VolumeSnapshotContent
// already deleted on cloud provider.
if apierrors.IsNotFound(err) {
p.Log.Warnf("VolumeSnapshotContent %s of backup %s cannot be found. May leave orphan snapshot %s on cloud provider.",
snapCont.Name, input.Backup.Name, *snapCont.Status.SnapshotHandle)
return nil
}
return errors.Wrapf(err, fmt.Sprintf("failed to set DeletionPolicy on volumesnapshotcontent %s. Skipping deletion", snapCont.Name))
}

err = snapClient.SnapshotV1().VolumeSnapshotContents().Delete(context.TODO(), snapCont.Name, metav1.DeleteOptions{})
if err != nil && !apierrors.IsNotFound(err) {
p.Log.Infof("VolumeSnapshotContent %s not found", snapCont.Name)
return err
}

return nil
}

func NewCsiVolumeSnapshotContentDeleteItemAction(logger logrus.FieldLogger) (interface{}, error) {
return &csiVolumeSnapshotContentDeleteItemAction{logger}, nil
}
45 changes: 45 additions & 0 deletions pkg/apis/velero/v1/labels_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ const (
// VolumesToExcludeAnnotation is the annotation on a pod whose mounted volumes
// should be excluded from pod volume backup.
VolumesToExcludeAnnotation = "backup.velero.io/backup-volumes-excludes"

// ExcludeFromBackupLabel is the label to exclude k8s resource from backup,
// even if the resource contains a matching selector label.
ExcludeFromBackupLabel = "velero.io/exclude-from-backup"
)

type AsyncOperationIDPrefix string
Expand All @@ -111,3 +115,44 @@ type VeleroResourceUsage string
const (
VeleroResourceUsageDataUploadResult VeleroResourceUsage = "DataUpload"
)

// CSI related plugin actions' constant variable
const (
VolumeSnapshotLabel = "velero.io/volume-snapshot-name"
VolumeSnapshotHandleAnnotation = "velero.io/csi-volumesnapshot-handle"
VolumeSnapshotRestoreSize = "velero.io/csi-volumesnapshot-restore-size"
DriverNameAnnotation = "velero.io/csi-driver-name"
DeleteSecretNameAnnotation = "velero.io/csi-deletesnapshotsecret-name" // #nosec G101
DeleteSecretNamespaceAnnotation = "velero.io/csi-deletesnapshotsecret-namespace" // #nosec G101
VSCDeletionPolicyAnnotation = "velero.io/csi-vsc-deletion-policy"
VolumeSnapshotClassSelectorLabel = "velero.io/csi-volumesnapshot-class"
VolumeSnapshotClassDriverBackupAnnotationPrefix = "velero.io/csi-volumesnapshot-class"
VolumeSnapshotClassDriverPVCAnnotation = "velero.io/csi-volumesnapshot-class"

// There is no release w/ these constants exported. Using the strings for now.
// CSI Annotation volumesnapshotclass
// https://github.com/kubernetes-csi/external-snapshotter/blob/master/pkg/utils/util.go#L59-L60
PrefixedListSecretNameAnnotation = "csi.storage.k8s.io/snapshotter-list-secret-name" // #nosec G101
PrefixedListSecretNamespaceAnnotation = "csi.storage.k8s.io/snapshotter-list-secret-namespace" // #nosec G101

// CSI Annotation volumesnapshotcontents
PrefixedSecretNameAnnotation = "csi.storage.k8s.io/snapshotter-secret-name" // #nosec G101
PrefixedSecretNamespaceAnnotation = "csi.storage.k8s.io/snapshotter-secret-namespace" // #nosec G101

// Velero checks this annotation to determine whether to skip resource excluding check.
MustIncludeAdditionalItemAnnotation = "backup.velero.io/must-include-additional-items"
// SkippedNoCSIPVAnnotation - Velero checks this annotation on processed PVC to
// find out if the snapshot was skipped b/c the PV is not provisioned via CSI
SkippedNoCSIPVAnnotation = "backup.velero.io/skipped-no-csi-pv"

// DynamicPVRestoreLabel is the label key for dynamic PV restore
DynamicPVRestoreLabel = "velero.io/dynamic-pv-restore"

// DataUploadNameAnnotation is the label key for the DataUpload name
DataUploadNameAnnotation = "velero.io/data-upload-name"
)

/*
csiBIAPluginName = "velero.io/csi-pvc-backupper"
vsphereBIAPluginName = "velero.io/vsphere-pvc-backupper"
*/
Loading

0 comments on commit 2001b16

Please sign in to comment.