mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-05 13:05:17 +00:00
Add result in backup VolumeInfo.
Signed-off-by: Xun Jiang <blackpigletbruce@gmail.com>
This commit is contained in:
@@ -92,6 +92,9 @@ type BackupVolumeInfo struct {
|
||||
// Snapshot completes timestamp.
|
||||
CompletionTimestamp *metav1.Time `json:"completionTimestamp,omitempty"`
|
||||
|
||||
// Whether the volume data is backed up successfully.
|
||||
Result VolumeResult `json:"result,omitempty"`
|
||||
|
||||
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
|
||||
SnapshotDataMovementInfo *SnapshotDataMovementInfo `json:"snapshotDataMovementInfo,omitempty"`
|
||||
NativeSnapshotInfo *NativeSnapshotInfo `json:"nativeSnapshotInfo,omitempty"`
|
||||
@@ -99,6 +102,14 @@ type BackupVolumeInfo struct {
|
||||
PVInfo *PVInfo `json:"pvInfo,omitempty"`
|
||||
}
|
||||
|
||||
type VolumeResult string
|
||||
|
||||
const (
|
||||
VolumeResultSucceeded VolumeResult = "succeeded"
|
||||
VolumeResultFailed VolumeResult = "failed"
|
||||
//VolumeResultCanceled VolumeResult = "canceled"
|
||||
)
|
||||
|
||||
type RestoreVolumeInfo struct {
|
||||
// The name of the restored PVC
|
||||
PVCName string `json:"pvcName,omitempty"`
|
||||
@@ -139,6 +150,9 @@ type CSISnapshotInfo struct {
|
||||
|
||||
// The Async Operation's ID.
|
||||
OperationID string `json:"operationID,omitempty"`
|
||||
|
||||
// The VolumeSnapshot's Status.ReadyToUse value
|
||||
ReadyToUse *bool
|
||||
}
|
||||
|
||||
// SnapshotDataMovementInfo is used for displaying the snapshot data mover status.
|
||||
@@ -162,6 +176,9 @@ type SnapshotDataMovementInfo struct {
|
||||
|
||||
// Moved snapshot data size.
|
||||
Size int64 `json:"size"`
|
||||
|
||||
// The DataUpload's Status.Phase value
|
||||
Phase velerov2alpha1.DataUploadPhase
|
||||
}
|
||||
|
||||
// NativeSnapshotInfo is used for displaying the Velero native snapshot status.
|
||||
@@ -180,6 +197,9 @@ type NativeSnapshotInfo struct {
|
||||
|
||||
// The cloud provider snapshot volume's IOPS.
|
||||
IOPS string `json:"iops"`
|
||||
|
||||
// The NativeSnapshot's Status.Phase value
|
||||
Phase SnapshotPhase
|
||||
}
|
||||
|
||||
func newNativeSnapshotInfo(s *Snapshot) *NativeSnapshotInfo {
|
||||
@@ -192,6 +212,7 @@ func newNativeSnapshotInfo(s *Snapshot) *NativeSnapshotInfo {
|
||||
VolumeType: s.Spec.VolumeType,
|
||||
VolumeAZ: s.Spec.VolumeAZ,
|
||||
IOPS: strconv.FormatInt(iops, 10),
|
||||
Phase: s.Status.Phase,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +240,9 @@ type PodVolumeInfo struct {
|
||||
// The PVB-taken k8s node's name.
|
||||
// This field will be empty when the struct is used to represent a podvolumerestore.
|
||||
NodeName string `json:"nodeName,omitempty"`
|
||||
|
||||
// The PVB's Status.Phase value
|
||||
Phase velerov1api.PodVolumeBackupPhase
|
||||
}
|
||||
|
||||
func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeInfo {
|
||||
@@ -230,6 +254,7 @@ func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeInfo {
|
||||
PodName: pvb.Spec.Pod.Name,
|
||||
PodNamespace: pvb.Spec.Pod.Namespace,
|
||||
NodeName: pvb.Spec.Node,
|
||||
Phase: pvb.Status.Phase,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,13 +374,20 @@ func (v *BackupVolumesInformation) generateVolumeInfoForVeleroNativeSnapshot() {
|
||||
|
||||
for _, nativeSnapshot := range v.NativeSnapshots {
|
||||
if pvcPVInfo := v.pvMap.retrieve(nativeSnapshot.Spec.PersistentVolumeName, "", ""); pvcPVInfo != nil {
|
||||
volumeResult := VolumeResultFailed
|
||||
if nativeSnapshot.Status.Phase == SnapshotPhaseCompleted {
|
||||
volumeResult = VolumeResultSucceeded
|
||||
}
|
||||
volumeInfo := &BackupVolumeInfo{
|
||||
BackupMethod: NativeSnapshot,
|
||||
PVCName: pvcPVInfo.PVCName,
|
||||
PVCNamespace: pvcPVInfo.PVCNamespace,
|
||||
PVName: pvcPVInfo.PV.Name,
|
||||
SnapshotDataMoved: false,
|
||||
Skipped: false,
|
||||
BackupMethod: NativeSnapshot,
|
||||
PVCName: pvcPVInfo.PVCName,
|
||||
PVCNamespace: pvcPVInfo.PVCNamespace,
|
||||
PVName: pvcPVInfo.PV.Name,
|
||||
SnapshotDataMoved: false,
|
||||
Skipped: false,
|
||||
// Only set Succeeded to true when the NativeSnapshot's phase is Completed,
|
||||
// although NativeSnapshot doesn't check whether the snapshot creation result.
|
||||
Result: volumeResult,
|
||||
NativeSnapshotInfo: newNativeSnapshotInfo(nativeSnapshot),
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: string(pvcPVInfo.PV.Spec.PersistentVolumeReclaimPolicy),
|
||||
@@ -451,6 +483,7 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
|
||||
Driver: volumeSnapshotClass.Driver,
|
||||
SnapshotHandle: snapshotHandle,
|
||||
OperationID: operation.Spec.OperationID,
|
||||
ReadyToUse: volumeSnapshot.Status.ReadyToUse,
|
||||
},
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: string(pvcPVInfo.PV.Spec.PersistentVolumeReclaimPolicy),
|
||||
@@ -484,6 +517,14 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromPVB() {
|
||||
CompletionTimestamp: pvb.Status.CompletionTimestamp,
|
||||
PVBInfo: newPodVolumeInfoFromPVB(pvb),
|
||||
}
|
||||
|
||||
// Only set Succeeded to true when the PVB's phase is Completed.
|
||||
if pvb.Status.Phase == velerov1api.PodVolumeBackupPhaseCompleted {
|
||||
volumeInfo.Result = VolumeResultSucceeded
|
||||
} else {
|
||||
volumeInfo.Result = VolumeResultFailed
|
||||
}
|
||||
|
||||
pvcName, err := pvcByPodvolume(context.TODO(), v.crClient, pvb.Spec.Pod.Name, pvb.Spec.Pod.Namespace, pvb.Spec.Volume)
|
||||
if err != nil {
|
||||
v.logger.WithError(err).Warn("Fail to get PVC from PodVolumeBackup: ", pvb.Name)
|
||||
@@ -582,6 +623,7 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
|
||||
DataMover: dataMover,
|
||||
UploaderType: kopia,
|
||||
OperationID: operation.Spec.OperationID,
|
||||
Phase: dataUpload.Status.Phase,
|
||||
},
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: string(pvcPVInfo.PV.Spec.PersistentVolumeReclaimPolicy),
|
||||
|
||||
@@ -200,6 +200,58 @@ func TestGenerateVolumeInfoForVeleroNativeSnapshot(t *testing.T) {
|
||||
},
|
||||
expectedVolumeInfos: []*BackupVolumeInfo{},
|
||||
},
|
||||
{
|
||||
name: "Normal native snapshot with failed phase",
|
||||
pvMap: map[string]pvcPvInfo{
|
||||
"testPV": {
|
||||
PVCName: "testPVC",
|
||||
PVCNamespace: "velero",
|
||||
PV: corev1api.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "testPV",
|
||||
Labels: map[string]string{"a": "b"},
|
||||
},
|
||||
Spec: corev1api.PersistentVolumeSpec{
|
||||
PersistentVolumeReclaimPolicy: corev1api.PersistentVolumeReclaimDelete,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
nativeSnapshot: Snapshot{
|
||||
Spec: SnapshotSpec{
|
||||
PersistentVolumeName: "testPV",
|
||||
VolumeIOPS: int64Ptr(100),
|
||||
VolumeType: "ssd",
|
||||
VolumeAZ: "us-central1-a",
|
||||
},
|
||||
Status: SnapshotStatus{
|
||||
ProviderSnapshotID: "pvc-b31e3386-4bbb-4937-95d-7934cd62-b0a1-494b-95d7-0687440e8d0c",
|
||||
Phase: SnapshotPhaseFailed,
|
||||
},
|
||||
},
|
||||
expectedVolumeInfos: []*BackupVolumeInfo{
|
||||
{
|
||||
PVCName: "testPVC",
|
||||
PVCNamespace: "velero",
|
||||
PVName: "testPV",
|
||||
BackupMethod: NativeSnapshot,
|
||||
Result: VolumeResultFailed,
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: "Delete",
|
||||
Labels: map[string]string{
|
||||
"a": "b",
|
||||
},
|
||||
},
|
||||
NativeSnapshotInfo: &NativeSnapshotInfo{
|
||||
SnapshotHandle: "pvc-b31e3386-4bbb-4937-95d-7934cd62-b0a1-494b-95d7-0687440e8d0c",
|
||||
VolumeType: "ssd",
|
||||
VolumeAZ: "us-central1-a",
|
||||
IOPS: "100",
|
||||
Phase: SnapshotPhaseFailed,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Normal native snapshot",
|
||||
pvMap: map[string]pvcPvInfo{
|
||||
@@ -226,6 +278,7 @@ func TestGenerateVolumeInfoForVeleroNativeSnapshot(t *testing.T) {
|
||||
},
|
||||
Status: SnapshotStatus{
|
||||
ProviderSnapshotID: "pvc-b31e3386-4bbb-4937-95d-7934cd62-b0a1-494b-95d7-0687440e8d0c",
|
||||
Phase: SnapshotPhaseCompleted,
|
||||
},
|
||||
},
|
||||
expectedVolumeInfos: []*BackupVolumeInfo{
|
||||
@@ -234,6 +287,7 @@ func TestGenerateVolumeInfoForVeleroNativeSnapshot(t *testing.T) {
|
||||
PVCNamespace: "velero",
|
||||
PVName: "testPV",
|
||||
BackupMethod: NativeSnapshot,
|
||||
Result: VolumeResultSucceeded,
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: "Delete",
|
||||
Labels: map[string]string{
|
||||
@@ -245,6 +299,7 @@ func TestGenerateVolumeInfoForVeleroNativeSnapshot(t *testing.T) {
|
||||
VolumeType: "ssd",
|
||||
VolumeAZ: "us-central1-a",
|
||||
IOPS: "100",
|
||||
Phase: SnapshotPhaseCompleted,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -274,6 +329,7 @@ func TestGenerateVolumeInfoForVeleroNativeSnapshot(t *testing.T) {
|
||||
func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
|
||||
resourceQuantity := resource.MustParse("100Gi")
|
||||
now := metav1.Now()
|
||||
readyToUse := true
|
||||
tests := []struct {
|
||||
name string
|
||||
volumeSnapshot snapshotv1api.VolumeSnapshot
|
||||
@@ -381,6 +437,7 @@ func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
|
||||
BoundVolumeSnapshotContentName: stringPtr("testContent"),
|
||||
CreationTime: &now,
|
||||
RestoreSize: &resourceQuantity,
|
||||
ReadyToUse: &readyToUse,
|
||||
},
|
||||
},
|
||||
volumeSnapshotClass: *builder.ForVolumeSnapshotClass("testClass").Driver("pd.csi.storage.gke.io").Result(),
|
||||
@@ -427,6 +484,7 @@ func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
|
||||
Size: 107374182400,
|
||||
VSCName: "testContent",
|
||||
OperationID: "testID",
|
||||
ReadyToUse: &readyToUse,
|
||||
},
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: "Delete",
|
||||
@@ -506,6 +564,7 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
|
||||
PVCNamespace: "",
|
||||
PVName: "",
|
||||
BackupMethod: PodVolumeBackup,
|
||||
Result: VolumeResultFailed,
|
||||
PVBInfo: &PodVolumeInfo{
|
||||
PodName: "testPod",
|
||||
PodNamespace: "velero",
|
||||
@@ -537,7 +596,7 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
|
||||
expectedVolumeInfos: []*BackupVolumeInfo{},
|
||||
},
|
||||
{
|
||||
name: "PVB's volume has a PVC",
|
||||
name: "PVB's volume has a PVC with failed phase",
|
||||
pvMap: map[string]pvcPvInfo{
|
||||
"testPV": {
|
||||
PVCName: "testPVC",
|
||||
@@ -553,7 +612,13 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
pvb: builder.ForPodVolumeBackup("velero", "testPVB").PodName("testPod").PodNamespace("velero").StartTimestamp(&now).CompletionTimestamp(&now).Result(),
|
||||
pvb: builder.ForPodVolumeBackup("velero", "testPVB").
|
||||
PodName("testPod").
|
||||
PodNamespace("velero").
|
||||
StartTimestamp(&now).
|
||||
CompletionTimestamp(&now).
|
||||
Phase(velerov1api.PodVolumeBackupPhaseFailed).
|
||||
Result(),
|
||||
pod: builder.ForPod("velero", "testPod").Containers(&corev1api.Container{
|
||||
Name: "test",
|
||||
VolumeMounts: []corev1api.VolumeMount{
|
||||
@@ -580,9 +645,74 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
|
||||
BackupMethod: PodVolumeBackup,
|
||||
StartTimestamp: &now,
|
||||
CompletionTimestamp: &now,
|
||||
Result: VolumeResultFailed,
|
||||
PVBInfo: &PodVolumeInfo{
|
||||
PodName: "testPod",
|
||||
PodNamespace: "velero",
|
||||
Phase: velerov1api.PodVolumeBackupPhaseFailed,
|
||||
},
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
|
||||
Labels: map[string]string{"a": "b"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PVB's volume has a PVC",
|
||||
pvMap: map[string]pvcPvInfo{
|
||||
"testPV": {
|
||||
PVCName: "testPVC",
|
||||
PVCNamespace: "velero",
|
||||
PV: corev1api.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "testPV",
|
||||
Labels: map[string]string{"a": "b"},
|
||||
},
|
||||
Spec: corev1api.PersistentVolumeSpec{
|
||||
PersistentVolumeReclaimPolicy: corev1api.PersistentVolumeReclaimDelete,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pvb: builder.ForPodVolumeBackup("velero", "testPVB").
|
||||
PodName("testPod").
|
||||
PodNamespace("velero").
|
||||
StartTimestamp(&now).
|
||||
CompletionTimestamp(&now).
|
||||
Phase(velerov1api.PodVolumeBackupPhaseCompleted).
|
||||
Result(),
|
||||
pod: builder.ForPod("velero", "testPod").Containers(&corev1api.Container{
|
||||
Name: "test",
|
||||
VolumeMounts: []corev1api.VolumeMount{
|
||||
{
|
||||
Name: "testVolume",
|
||||
MountPath: "/data",
|
||||
},
|
||||
},
|
||||
}).Volumes(
|
||||
&corev1api.Volume{
|
||||
Name: "",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{
|
||||
ClaimName: "testPVC",
|
||||
},
|
||||
},
|
||||
},
|
||||
).Result(),
|
||||
expectedVolumeInfos: []*BackupVolumeInfo{
|
||||
{
|
||||
PVCName: "testPVC",
|
||||
PVCNamespace: "velero",
|
||||
PVName: "testPV",
|
||||
BackupMethod: PodVolumeBackup,
|
||||
StartTimestamp: &now,
|
||||
CompletionTimestamp: &now,
|
||||
Result: VolumeResultSucceeded,
|
||||
PVBInfo: &PodVolumeInfo{
|
||||
PodName: "testPod",
|
||||
PodNamespace: "velero",
|
||||
Phase: velerov1api.PodVolumeBackupPhaseCompleted,
|
||||
},
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
|
||||
@@ -770,10 +900,15 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Normal DataUpload case",
|
||||
dataUpload: builder.ForDataUpload("velero", "testDU").DataMover("velero").CSISnapshot(&velerov2alpha1.CSISnapshotSpec{
|
||||
VolumeSnapshot: "testVS",
|
||||
SnapshotClass: "testClass",
|
||||
}).SnapshotID("testSnapshotHandle").StartTimestamp(&now).Result(),
|
||||
dataUpload: builder.ForDataUpload("velero", "testDU").
|
||||
DataMover("velero").
|
||||
CSISnapshot(&velerov2alpha1.CSISnapshotSpec{
|
||||
VolumeSnapshot: "testVS",
|
||||
SnapshotClass: "testClass",
|
||||
}).SnapshotID("testSnapshotHandle").
|
||||
StartTimestamp(&now).
|
||||
Phase(velerov2alpha1.DataUploadPhaseCompleted).
|
||||
Result(),
|
||||
volumeSnapshotClass: builder.ForVolumeSnapshotClass("testClass").Driver("pd.csi.storage.gke.io").Result(),
|
||||
operation: &itemoperation.BackupOperation{
|
||||
Spec: itemoperation.BackupOperationSpec{
|
||||
@@ -832,6 +967,7 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
|
||||
DataMover: "velero",
|
||||
UploaderType: "kopia",
|
||||
OperationID: "testOperation",
|
||||
Phase: velerov2alpha1.DataUploadPhaseCompleted,
|
||||
},
|
||||
PVInfo: &PVInfo{
|
||||
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
|
||||
|
||||
Reference in New Issue
Block a user