mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-09-19 22:44:21 +00:00
@@ -108,7 +108,6 @@ type PVInfo struct {
|
||||
### How the VolumeInfo array is generated.
|
||||
The function `persistBackup` has `backup *pkgbackup.Request` in parameters.
|
||||
From it, the `VolumeSnapshots`, `PodVolumeBackups`, `CSISnapshots`, `itemOperationsList`, and `SkippedPVTracker` can be read. All of them will be iterated and merged into the `VolumeInfo` array, and then persisted into backup repository in function `persistBackup`.
|
||||
After going through all the available sources, Velero will check whether there are still some PVs left. If there is any, Velero will generate VolumeInfo for them. The VolumeInfo will contain the PVC namespace, PVC name, PV name and the PVInfo structure.
|
||||
|
||||
Please notice that the change happened in async operations are not reflected in the new metadata file. The file only covers the volume changes happen in the Velero server process scope.
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ func Stream(ctx context.Context, kbClient kbclient.Client, namespace, name strin
|
||||
ExpectContinueTimeout: defaultTransport.ExpectContinueTimeout,
|
||||
}
|
||||
|
||||
httpReq, err := http.NewRequest(http.MethodGet, created.Status.DownloadURL, nil)
|
||||
httpReq, err := http.NewRequestWithContext(context.TODO(), http.MethodGet, created.Status.DownloadURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -523,8 +523,9 @@ func (r *restoreReconciler) runValidatedRestore(restore *api.Restore, info backu
|
||||
|
||||
backupVolumeInfoMap := make(map[string]internalVolume.VolumeInfo)
|
||||
volumeInfos, err := backupStore.GetBackupVolumeInfos(restore.Spec.BackupName)
|
||||
if err != nil || len(volumeInfos) == 0 {
|
||||
restoreLog.Infof("Backup %s doesn't have volumeinfos metadata file.", restore.Spec.BackupName)
|
||||
if err != nil {
|
||||
restoreLog.WithError(err).Errorf("fail to get VolumeInfos metadata file for backup %s", restore.Spec.BackupName)
|
||||
return errors.WithStack(err)
|
||||
} else {
|
||||
for _, volumeInfo := range volumeInfos {
|
||||
backupVolumeInfoMap[volumeInfo.PVName] = *volumeInfo
|
||||
|
||||
+103
-87
@@ -81,15 +81,6 @@ var resourceMustHave = []string{
|
||||
"datauploads.velero.io",
|
||||
}
|
||||
|
||||
const (
|
||||
pvHasNativeSnapshot = iota + 1
|
||||
pvHasPodVolumeBackup
|
||||
pvHasCSIVolumeSnapshot
|
||||
pvHasDataUpload
|
||||
pvHasReclaimPolicyAsDelete
|
||||
pvHasReclaimPolicyAsRetain
|
||||
)
|
||||
|
||||
type VolumeSnapshotterGetter interface {
|
||||
GetVolumeSnapshotter(name string) (vsv1.VolumeSnapshotter, error)
|
||||
}
|
||||
@@ -1244,28 +1235,56 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
}
|
||||
|
||||
if groupResource == kuberesource.PersistentVolumes {
|
||||
pvCondition := 0
|
||||
if volumeInfo, ok := ctx.volumeInfoMap[obj.GetName()]; ok {
|
||||
ctx.log.Infof("Find VolumeInfo for PV %s.", obj.GetName())
|
||||
|
||||
switch volumeInfo.BackupMethod {
|
||||
case internalVolume.NativeSnapshot:
|
||||
pvCondition = pvHasNativeSnapshot
|
||||
case internalVolume.PodVolumeBackup:
|
||||
pvCondition = pvHasPodVolumeBackup
|
||||
case internalVolume.CSISnapshot:
|
||||
if volumeInfo.SnapshotDataMoved {
|
||||
pvCondition = pvHasDataUpload
|
||||
} else {
|
||||
pvCondition = pvHasCSIVolumeSnapshot
|
||||
obj, err = ctx.handlePVHasNativeSnapshot(obj, resourceClient)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
|
||||
name = obj.GetName()
|
||||
|
||||
case internalVolume.PodVolumeBackup:
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it has a pod volume backup to be restored.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
case internalVolume.CSISnapshot:
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it has a CSI VolumeSnapshot or a related snapshot DataUpload.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
if ready, err := ctx.featureVerifier.Verify(velerov1api.CSIFeatureFlag); !ready {
|
||||
ctx.log.Errorf("Failed to verify CSI modules, ready %v, err %v", ready, err)
|
||||
errs.Add(namespace, fmt.Errorf("CSI modules are not ready for restore. Check CSI feature is enabled and CSI plugin is installed"))
|
||||
}
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
// When the PV data is skipped from backup, it's VolumeInfo BackupMethod
|
||||
// is not set, and it will fall into the default case.
|
||||
default:
|
||||
if hasDeleteReclaimPolicy(obj.Object) {
|
||||
pvCondition = pvHasReclaimPolicyAsDelete
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it doesn't have a snapshot and its reclaim policy is Delete.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
} else {
|
||||
pvCondition = pvHasReclaimPolicyAsRetain
|
||||
obj, err = ctx.handleSkippedPVHasRetainPolicy(obj, resourceID, restoreLogger)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1275,80 +1294,53 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
|
||||
switch {
|
||||
case hasSnapshot(name, ctx.volumeSnapshots):
|
||||
pvCondition = pvHasNativeSnapshot
|
||||
obj, err = ctx.handlePVHasNativeSnapshot(obj, resourceClient)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
|
||||
name = obj.GetName()
|
||||
|
||||
case hasPodVolumeBackup(obj, ctx):
|
||||
pvCondition = pvHasPodVolumeBackup
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it has a pod volume backup to be restored.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
case hasCSIVolumeSnapshot(ctx, obj):
|
||||
pvCondition = pvHasCSIVolumeSnapshot
|
||||
fallthrough
|
||||
case hasSnapshotDataUpload(ctx, obj):
|
||||
pvCondition = pvHasDataUpload
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it has a CSI VolumeSnapshot or a related snapshot DataUpload.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
if ready, err := ctx.featureVerifier.Verify(velerov1api.CSIFeatureFlag); !ready {
|
||||
ctx.log.Errorf("Failed to verify CSI modules, ready %v, err %v", ready, err)
|
||||
errs.Add(namespace, fmt.Errorf("CSI modules are not ready for restore. Check CSI feature is enabled and CSI plugin is installed"))
|
||||
}
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
case hasDeleteReclaimPolicy(obj.Object):
|
||||
pvCondition = pvHasReclaimPolicyAsDelete
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it doesn't have a snapshot and its reclaim policy is Delete.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
default:
|
||||
pvCondition = pvHasReclaimPolicyAsRetain
|
||||
obj, err = ctx.handleSkippedPVHasRetainPolicy(obj, resourceID, restoreLogger)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch pvCondition {
|
||||
case pvHasNativeSnapshot:
|
||||
obj, err = ctx.handlePVHasNativeSnapshot(obj, resourceClient)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
|
||||
name = obj.GetName()
|
||||
|
||||
case pvHasPodVolumeBackup:
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it has a pod volume backup to be restored.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
case pvHasCSIVolumeSnapshot:
|
||||
fallthrough
|
||||
case pvHasDataUpload:
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it has a CSI VolumeSnapshot or a related snapshot DataUpload.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
if ready, err := ctx.featureVerifier.Verify(velerov1api.CSIFeatureFlag); !ready {
|
||||
ctx.log.Errorf("Failed to verify CSI modules, ready %v, err %v", ready, err)
|
||||
errs.Add(namespace, fmt.Errorf("CSI modules are not ready for restore. Check CSI feature is enabled and CSI plugin is installed"))
|
||||
}
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
case pvHasReclaimPolicyAsDelete:
|
||||
restoreLogger.Infof("Dynamically re-provisioning persistent volume because it doesn't have a snapshot and its reclaim policy is Delete.")
|
||||
ctx.pvsToProvision.Insert(name)
|
||||
|
||||
// Return early because we don't want to restore the PV itself, we
|
||||
// want to dynamically re-provision it.
|
||||
return warnings, errs, itemExists
|
||||
|
||||
case pvHasReclaimPolicyAsRetain:
|
||||
restoreLogger.Infof("Restoring persistent volume as-is because it doesn't have a snapshot and its reclaim policy is not Delete.")
|
||||
|
||||
// Check to see if the claimRef.namespace field needs to be remapped, and do so if necessary.
|
||||
_, err = remapClaimRefNS(ctx, obj)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
obj = resetVolumeBindingInfo(obj)
|
||||
// We call the pvRestorer here to clear out the PV's claimRef.UID,
|
||||
// so it can be re-claimed when its PVC is restored and gets a new UID.
|
||||
updatedObj, err := ctx.pvRestorer.executePVAction(obj)
|
||||
if err != nil {
|
||||
errs.Add(namespace, fmt.Errorf("error executing PVAction for %s: %v", resourceID, err))
|
||||
return warnings, errs, itemExists
|
||||
}
|
||||
obj = updatedObj
|
||||
}
|
||||
}
|
||||
|
||||
objStatus, statusFieldExists, statusFieldErr := unstructured.NestedFieldCopy(obj.Object, "status")
|
||||
@@ -2517,3 +2509,27 @@ func (ctx *restoreContext) handlePVHasNativeSnapshot(obj *unstructured.Unstructu
|
||||
|
||||
return retObj, nil
|
||||
}
|
||||
|
||||
func (ctx *restoreContext) handleSkippedPVHasRetainPolicy(
|
||||
obj *unstructured.Unstructured,
|
||||
resourceID string,
|
||||
logger logrus.FieldLogger,
|
||||
) (*unstructured.Unstructured, error) {
|
||||
logger.Infof("Restoring persistent volume as-is because it doesn't have a snapshot and its reclaim policy is not Delete.")
|
||||
|
||||
// Check to see if the claimRef.namespace field needs to be remapped, and do so if necessary.
|
||||
if _, err := remapClaimRefNS(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obj = resetVolumeBindingInfo(obj)
|
||||
|
||||
// We call the pvRestorer here to clear out the PV's claimRef.UID,
|
||||
// so it can be re-claimed when its PVC is restored and gets a new UID.
|
||||
updatedObj, err := ctx.pvRestorer.executePVAction(obj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error executing PVAction for %s: %v", resourceID, err)
|
||||
}
|
||||
|
||||
return updatedObj, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user