Skip to content

Commit

Permalink
Merge pull request #7775 from blackpiglet/add_volume_backup_result
Browse files Browse the repository at this point in the history
Add volume backup result
  • Loading branch information
Lyndon-Li authored Jul 2, 2024
2 parents ff63486 + df28134 commit 28d64c2
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 23 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/7775-blackpiglet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the result in the backup's VolumeInfo.
54 changes: 48 additions & 6 deletions internal/volume/volumes_information.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,24 @@ 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"`
PVBInfo *PodVolumeInfo `json:"pvbInfo,omitempty"`
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"`
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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 {
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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),
Expand Down
146 changes: 141 additions & 5 deletions internal/volume/volumes_information_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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{
Expand All @@ -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{
Expand All @@ -245,6 +299,7 @@ func TestGenerateVolumeInfoForVeleroNativeSnapshot(t *testing.T) {
VolumeType: "ssd",
VolumeAZ: "us-central1-a",
IOPS: "100",
Phase: SnapshotPhaseCompleted,
},
},
},
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -427,6 +484,7 @@ func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
Size: 107374182400,
VSCName: "testContent",
OperationID: "testID",
ReadyToUse: &readyToUse,
},
PVInfo: &PVInfo{
ReclaimPolicy: "Delete",
Expand Down Expand Up @@ -506,6 +564,7 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
PVCNamespace: "",
PVName: "",
BackupMethod: PodVolumeBackup,
Result: VolumeResultFailed,
PVBInfo: &PodVolumeInfo{
PodName: "testPod",
PodNamespace: "velero",
Expand Down Expand Up @@ -536,6 +595,69 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
).Result(),
expectedVolumeInfos: []*BackupVolumeInfo{},
},
{
name: "PVB's volume has a PVC 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,
},
},
},
},
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{
{
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: 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{
Expand All @@ -553,7 +675,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.PodVolumeBackupPhaseCompleted).
Result(),
pod: builder.ForPod("velero", "testPod").Containers(&corev1api.Container{
Name: "test",
VolumeMounts: []corev1api.VolumeMount{
Expand All @@ -580,9 +708,11 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
BackupMethod: PodVolumeBackup,
StartTimestamp: &now,
CompletionTimestamp: &now,
Result: VolumeResultSucceeded,
PVBInfo: &PodVolumeInfo{
PodName: "testPod",
PodNamespace: "velero",
Phase: velerov1api.PodVolumeBackupPhaseCompleted,
},
PVInfo: &PVInfo{
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -832,6 +967,7 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
DataMover: "velero",
UploaderType: "kopia",
OperationID: "testOperation",
Phase: velerov2alpha1.DataUploadPhaseCompleted,
},
PVInfo: &PVInfo{
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
Expand Down
Loading

0 comments on commit 28d64c2

Please sign in to comment.