Restore from PodVolumeBackups (#1723)

* Restore from PodVolumeBackups

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Partially address code reviews

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Partially address code reviews #2

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Clean up struct

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Fix log messages

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Fix tests

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Clean up

Signed-off-by: Carlisia <carlisiac@vmware.com>

* Add changelog

Signed-off-by: Carlisia <carlisiac@vmware.com>
This commit is contained in:
KubeKween
2019-08-06 13:17:36 -07:00
committed by Adnan Abdulhussein
parent 4e1b1f9457
commit 4accb8512a
11 changed files with 321 additions and 139 deletions

View File

@@ -45,10 +45,12 @@ const (
volumesToBackupAnnotation = "backup.velero.io/backup-volumes"
)
// GetPodSnapshotAnnotations returns a map, of volume name -> snapshot id,
// getPodSnapshotAnnotations returns a map, of volume name -> snapshot id,
// of all restic snapshots for this pod.
// Deprecated: we will stop using pod annotations to record restic snapshot IDs after they're taken.
func GetPodSnapshotAnnotations(obj metav1.Object) map[string]string {
// TODO(2.0) to remove
// Deprecated: we will stop using pod annotations to record restic snapshot IDs after they're taken,
// therefore we won't need to check if these annotations exist.
func getPodSnapshotAnnotations(obj metav1.Object) map[string]string {
var res map[string]string
insertSafe := func(k, v string) {
@@ -67,6 +69,24 @@ func GetPodSnapshotAnnotations(obj metav1.Object) map[string]string {
return res
}
// GetVolumeBackupsForPod returns a map, of volume name -> snapshot id,
// of the PodVolumeBackups that exist for the provided pod.
func GetVolumeBackupsForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, pod metav1.Object) map[string]string {
volumes := make(map[string]string)
for _, pvb := range podVolumeBackups {
if pod.GetName() == pvb.Spec.Pod.Name {
volumes[pvb.Spec.Volume] = pvb.Status.SnapshotID
}
}
if len(volumes) > 0 {
return volumes
}
return getPodSnapshotAnnotations(pod)
}
// GetVolumesToBackup returns a list of volume names to backup for
// the provided pod.
func GetVolumesToBackup(obj metav1.Object) []string {

View File

@@ -75,7 +75,7 @@ func TestGetPodSnapshotAnnotations(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
pod := &corev1api.Pod{}
pod.Annotations = test.annotations
assert.Equal(t, test.expected, GetPodSnapshotAnnotations(pod))
assert.Equal(t, test.expected, getPodSnapshotAnnotations(pod))
})
}
}

View File

@@ -31,10 +31,17 @@ import (
"github.com/heptio/velero/pkg/util/boolptr"
)
type RestoreData struct {
Restore *velerov1api.Restore
Pod *corev1api.Pod
PodVolumeBackups []*velerov1api.PodVolumeBackup
SourceNamespace, BackupLocation string
}
// Restorer can execute restic restores of volumes in a pod.
type Restorer interface {
// RestorePodVolumes restores all annotated volumes in a pod.
RestorePodVolumes(restore *velerov1api.Restore, pod *corev1api.Pod, sourceNamespace, backupLocation string, log logrus.FieldLogger) []error
RestorePodVolumes(RestoreData) []error
}
type restorer struct {
@@ -84,14 +91,13 @@ func newRestorer(
return r
}
func (r *restorer) RestorePodVolumes(restore *velerov1api.Restore, pod *corev1api.Pod, sourceNamespace, backupLocation string, log logrus.FieldLogger) []error {
// get volumes to restore from pod's annotations
volumesToRestore := GetPodSnapshotAnnotations(pod)
func (r *restorer) RestorePodVolumes(data RestoreData) []error {
volumesToRestore := GetVolumeBackupsForPod(data.PodVolumeBackups, data.Pod)
if len(volumesToRestore) == 0 {
return nil
}
repo, err := r.repoEnsurer.EnsureRepo(r.ctx, restore.Namespace, sourceNamespace, backupLocation)
repo, err := r.repoEnsurer.EnsureRepo(r.ctx, data.Restore.Namespace, data.SourceNamespace, data.BackupLocation)
if err != nil {
return []error{err}
}
@@ -104,7 +110,7 @@ func (r *restorer) RestorePodVolumes(restore *velerov1api.Restore, pod *corev1ap
resultsChan := make(chan *velerov1api.PodVolumeRestore)
r.resultsLock.Lock()
r.results[resultsKey(pod.Namespace, pod.Name)] = resultsChan
r.results[resultsKey(data.Pod.Namespace, data.Pod.Name)] = resultsChan
r.resultsLock.Unlock()
var (
@@ -113,7 +119,7 @@ func (r *restorer) RestorePodVolumes(restore *velerov1api.Restore, pod *corev1ap
)
for volume, snapshot := range volumesToRestore {
volumeRestore := newPodVolumeRestore(restore, pod, volume, snapshot, backupLocation, repo.Spec.ResticIdentifier)
volumeRestore := newPodVolumeRestore(data.Restore, data.Pod, data.BackupLocation, volume, snapshot, repo.Spec.ResticIdentifier)
if err := errorOnly(r.repoManager.veleroClient.VeleroV1().PodVolumeRestores(volumeRestore.Namespace).Create(volumeRestore)); err != nil {
errs = append(errs, errors.WithStack(err))
@@ -136,13 +142,13 @@ ForEachVolume:
}
r.resultsLock.Lock()
delete(r.results, resultsKey(pod.Namespace, pod.Name))
delete(r.results, resultsKey(data.Pod.Namespace, data.Pod.Name))
r.resultsLock.Unlock()
return errs
}
func newPodVolumeRestore(restore *velerov1api.Restore, pod *corev1api.Pod, volume, snapshot, backupLocation, repoIdentifier string) *velerov1api.PodVolumeRestore {
func newPodVolumeRestore(restore *velerov1api.Restore, pod *corev1api.Pod, backupLocation, volume, snapshot, repoIdentifier string) *velerov1api.PodVolumeRestore {
return &velerov1api.PodVolumeRestore{
ObjectMeta: metav1.ObjectMeta{
Namespace: restore.Namespace,