-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extend Volume Policies feature to support more actions
Signed-off-by: Shubham Pampattiwar <[email protected]> fix volume policy action execution Signed-off-by: Shubham Pampattiwar <[email protected]> remove unused files Signed-off-by: Shubham Pampattiwar <[email protected]> add changelog file Signed-off-by: Shubham Pampattiwar <[email protected]> fix CI linter errors fix linter errors address pr review comments Signed-off-by: Shubham Pampattiwar <[email protected]> fix via make update cmd Signed-off-by: Shubham Pampattiwar <[email protected]>
- Loading branch information
1 parent
22b9465
commit f96d570
Showing
10 changed files
with
423 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Implementation for Extending VolumePolicies to support more actions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
package volumehelper | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/vmware-tanzu/velero/pkg/util/boolptr" | ||
kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" | ||
|
||
"github.com/sirupsen/logrus" | ||
corev1api "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
|
||
"github.com/vmware-tanzu/velero/internal/resourcepolicies" | ||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" | ||
"github.com/vmware-tanzu/velero/pkg/client" | ||
"github.com/vmware-tanzu/velero/pkg/kuberesource" | ||
"github.com/vmware-tanzu/velero/pkg/util" | ||
pdvolumeutil "github.com/vmware-tanzu/velero/pkg/util/podvolume" | ||
) | ||
|
||
type VolumeHelper interface { | ||
GetVolumesForFSBackup(pod *corev1api.Pod) ([]string, []string, error) | ||
ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error) | ||
} | ||
|
||
type VolumeHelperImpl struct { | ||
Backup *velerov1api.Backup | ||
VolumePolicy *resourcepolicies.Policies | ||
SnapshotVolumes *bool | ||
Logger logrus.FieldLogger | ||
DynamicFactory client.DynamicFactory | ||
} | ||
|
||
func (v *VolumeHelperImpl) ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error) { | ||
// check if volume policy exists and also check if the object(pv/pvc) fits a volume policy criteria and see if the associated action is snapshot | ||
// if it is not snapshot then skip the code path for snapshotting the PV/PVC | ||
pvc := new(corev1api.PersistentVolumeClaim) | ||
pv := new(corev1api.PersistentVolume) | ||
var err error | ||
|
||
if groupResource == kuberesource.PersistentVolumeClaims { | ||
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pvc); err != nil { | ||
return false, err | ||
} | ||
|
||
pv, err = v.GetPVForPVC(pvc) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
} | ||
|
||
if groupResource == kuberesource.PersistentVolumes { | ||
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pv); err != nil { | ||
return false, err | ||
} | ||
} | ||
|
||
if v.VolumePolicy != nil { | ||
action, err := v.VolumePolicy.GetMatchAction(pv) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
// Also account for SnapshotVolumes flag on backup CR | ||
if action != nil && action.Type == resourcepolicies.Snapshot && boolptr.IsSetToTrue(v.SnapshotVolumes) { | ||
v.Logger.Infof(fmt.Sprintf("performing snapshot action for pv %s as it satisfies the volume policy criteria and snapshotVolumes is set to true", pv.Name)) | ||
return true, nil | ||
} | ||
v.Logger.Infof(fmt.Sprintf("skipping snapshot action for pv %s possibly due to not satisfying the volume policy criteria or snapshotVolumes is not true", pv.Name)) | ||
return false, nil | ||
} | ||
|
||
return false, nil | ||
} | ||
|
||
func (v *VolumeHelperImpl) GetVolumesForFSBackup(pod *corev1api.Pod, defaultVolumesToFsBackup, backupExcludePVC bool) ([]string, []string, error) { | ||
// Check if there is a fs-backup/snapshot volume policy specified by the user, if yes then use the volume policy approach to | ||
// get the list volumes for fs-backup else go via the legacy annotation based approach | ||
var includedVolumes, optedOutVolumes, volsToProcessByLegacyApproach = make([]string, 0), make([]string, 0), make([]string, 0) | ||
var err error | ||
|
||
if v.VolumePolicy != nil { | ||
// Get the list of volumes to back up using pod volume backup for the given pod matching fs-backup volume policy action | ||
v.Logger.Infof("Volume Policy specified by the user, using volume policy approach to segregate pod volumes for fs-backup") | ||
includedVolumes, optedOutVolumes, volsToProcessByLegacyApproach, err = v.GetVolumesMatchingFSBackupAction(pod, v.VolumePolicy, backupExcludePVC) | ||
if err != nil { | ||
return includedVolumes, optedOutVolumes, err | ||
} | ||
} | ||
|
||
// process legacy annotation based approach, this will be done for 2 scenarios: | ||
// 1. volume policy not specified by the user | ||
// 2. there are some volumes for which the volume policy approach did not get any supported matching actions | ||
if v.VolumePolicy == nil || len(volsToProcessByLegacyApproach) > 0 { | ||
// Get the list of volumes to back up using pod volume backup from the pod's annotations. | ||
// We will also pass the list of volume that did not have any supported volume policy action matched in legacy approach so that | ||
// those volumes get processed via legacy annotation based approach, this is a fallback option on annotation based legacy approach | ||
v.Logger.Infof("fs-backup or snapshot Volume Policy not specified by the user, using legacy approach based on annotations") | ||
includedVolumes, optedOutVolumes = pdvolumeutil.GetVolumesByPod(pod, defaultVolumesToFsBackup, backupExcludePVC, volsToProcessByLegacyApproach) | ||
} | ||
return includedVolumes, optedOutVolumes, nil | ||
} | ||
|
||
// GetVolumesMatchingFSBackupAction returns a list of volume names to backup for the provided pod having fs-backup volume policy action | ||
func (v *VolumeHelperImpl) GetVolumesMatchingFSBackupAction(pod *corev1api.Pod, volumePolicies *resourcepolicies.Policies, backupExcludePVC bool) ([]string, []string, []string, error) { | ||
FSBackupActionMatchingVols := []string{} | ||
FSBackupNonActionMatchingVols := []string{} | ||
NoActionMatchingVols := []string{} | ||
|
||
volsToExclude := pdvolumeutil.GetVolumesToExclude(pod) | ||
for _, vol := range pod.Spec.Volumes { | ||
if !v.ShouldIncludeVolumeInBackup(vol, volsToExclude, backupExcludePVC) { | ||
continue | ||
} | ||
// don't backup volumes that are included in the exclude list. | ||
if util.Contains(volsToExclude, vol.Name) { | ||
FSBackupNonActionMatchingVols = append(FSBackupNonActionMatchingVols, vol.Name) | ||
} | ||
|
||
if vol.PersistentVolumeClaim != nil { | ||
// fetch the associated PVC first | ||
pvc, err := kubeutil.GetPVCForPodVolume(vol, pod, v.DynamicFactory) | ||
if err != nil { | ||
return FSBackupActionMatchingVols, FSBackupNonActionMatchingVols, NoActionMatchingVols, err | ||
} | ||
// now fetch the PV and call GetMatchAction on it | ||
pv, err := v.GetPVForPVC(pvc) | ||
if err != nil { | ||
return FSBackupActionMatchingVols, FSBackupNonActionMatchingVols, NoActionMatchingVols, err | ||
} | ||
// now get the action for pv | ||
action, err := volumePolicies.GetMatchAction(pv) | ||
if err != nil { | ||
return FSBackupActionMatchingVols, FSBackupNonActionMatchingVols, NoActionMatchingVols, err | ||
} | ||
|
||
// Record volume list having at least some action so that they are not processed in legacy fallback option | ||
if action == nil { | ||
NoActionMatchingVols = append(NoActionMatchingVols, vol.Name) | ||
} | ||
|
||
// Now if the matched action is not nil and is `fs-backup` then add that Volume to the FSBackupActionMatchingVols | ||
// else add that volume to FSBackupNonActionMatchingVols | ||
// we already tracked the volume not matching any kind actions supported by volume policy in NoActionMatchingVols | ||
// The NoActionMatchingVols list will be processed via legacy annotation based approach as a fallback option | ||
if action != nil && action.Type == resourcepolicies.FSBackup { | ||
FSBackupActionMatchingVols = append(FSBackupActionMatchingVols, vol.Name) | ||
} else { | ||
FSBackupNonActionMatchingVols = append(FSBackupNonActionMatchingVols, vol.Name) | ||
} | ||
} | ||
} | ||
return FSBackupActionMatchingVols, FSBackupNonActionMatchingVols, NoActionMatchingVols, nil | ||
} | ||
|
||
func (v *VolumeHelperImpl) ShouldIncludeVolumeInBackup(vol corev1api.Volume, volsToExclude []string, backupExcludePVC bool) bool { | ||
includeVolumeInBackup := true | ||
// cannot backup hostpath volumes as they are not mounted into /var/lib/kubelet/pods | ||
// and therefore not accessible to the node agent daemon set. | ||
if vol.HostPath != nil { | ||
includeVolumeInBackup = false | ||
} | ||
// don't backup volumes mounting secrets. Secrets will be backed up separately. | ||
if vol.Secret != nil { | ||
includeVolumeInBackup = false | ||
} | ||
// don't backup volumes mounting ConfigMaps. ConfigMaps will be backed up separately. | ||
if vol.ConfigMap != nil { | ||
includeVolumeInBackup = false | ||
} | ||
// don't backup volumes mounted as projected volumes, all data in those come from kube state. | ||
if vol.Projected != nil { | ||
includeVolumeInBackup = false | ||
} | ||
// don't backup DownwardAPI volumes, all data in those come from kube state. | ||
if vol.DownwardAPI != nil { | ||
includeVolumeInBackup = false | ||
} | ||
if vol.PersistentVolumeClaim != nil && backupExcludePVC { | ||
includeVolumeInBackup = false | ||
} | ||
// don't backup volumes that are included in the exclude list. | ||
if util.Contains(volsToExclude, vol.Name) { | ||
includeVolumeInBackup = false | ||
} | ||
// don't include volumes that mount the default service account token. | ||
if strings.HasPrefix(vol.Name, "default-token") { | ||
includeVolumeInBackup = false | ||
} | ||
return includeVolumeInBackup | ||
} | ||
|
||
func (v *VolumeHelperImpl) GetPVForPVC(pvc *corev1api.PersistentVolumeClaim) (*corev1api.PersistentVolume, error) { | ||
pvResource := metav1.APIResource{Name: "persistentvolumes", Namespaced: false} | ||
pvClient, err := v.DynamicFactory.ClientForGroupVersionResource(schema.GroupVersion{Group: "", Version: "v1"}, pvResource, "") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
pvObject, err := pvClient.Get(pvc.Spec.VolumeName, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
pv := new(corev1api.PersistentVolume) | ||
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(pvObject.UnstructuredContent(), pv); err != nil { | ||
return nil, err | ||
} | ||
return pv, nil | ||
} |
Oops, something went wrong.