Move the progress messages to activities (#10552)
Run the E2E test on kind / setup-test-matrix (push) Failing after 3s
Scorecard supply-chain security / Scorecard analysis (push) Skipped
e2e-test-kind.yaml / extract (push) Failing after 8s
Run the E2E test on kind / get-go-version (push) Failing after 10s
Run the E2E test on kind / build (push) Skipped
Run the E2E test on kind / run-e2e-test (push) Skipped
push.yml / extract (push) Failing after 6s
Main CI / get-go-version (push) Failing after 7s
Main CI / Build (push) Skipped

* move the progress messages to activities

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>

* update doc for activities in data mover CR

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>

---------

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
lyndon-li
2026-09-22 14:24:05 +08:00
committed by GitHub
parent 3793d9ab4a
commit 0a2f5278b2
13 changed files with 76 additions and 25 deletions
@@ -98,7 +98,7 @@ type PodVolumeBackupStatus struct {
// +optional
SnapshotID string `json:"snapshotID,omitempty"`
// Message is a message about the pod volume backup's status.
// Message is a message describing the pod volume backup when it reaches to a terminal status.
// +optional
Message string `json:"message,omitempty"`
@@ -144,6 +144,11 @@ type PodVolumeBackupStatus struct {
// FallbackFull indicates whether the incremental backup has fallen back to full backup
FallbackFull bool `json:"fallbackFull,omitempty"`
// Activities contains one or more messages about what have been done for this pod volume backup.
// +optional
// +nullable
Activities []string `json:"activities,omitempty"`
}
// TODO(2.0) After converting all resources to use the runttime-controller client,
@@ -88,7 +88,7 @@ type PodVolumeRestoreStatus struct {
// +optional
Phase PodVolumeRestorePhase `json:"phase,omitempty"`
// Message is a message about the pod volume restore's status.
// Message is a message describing the pod volume restore when it reaches to a terminal status.
// +optional
Message string `json:"message,omitempty"`
@@ -127,6 +127,11 @@ type PodVolumeRestoreStatus struct {
// FallbackFull indicates whether the incremental restore has fallen back to full restore
FallbackFull bool `json:"fallbackFull,omitempty"`
// Activities contains one or more messages about what have been done for this pod volume restore.
// +optional
// +nullable
Activities []string `json:"activities,omitempty"`
}
// TODO(2.0) After converting all resources to use the runtime-controller client, the genclient and k8s:deepcopy markers will no longer be needed and should be removed.
@@ -109,7 +109,7 @@ type DataDownloadStatus struct {
// +optional
Phase DataDownloadPhase `json:"phase,omitempty"`
// Message is a message about the DataDownload's status.
// Message is a message describing the DataDownload when it reaches to a terminal status.
// +optional
Message string `json:"message,omitempty"`
@@ -152,6 +152,11 @@ type DataDownloadStatus struct {
// FallbackFull indicates whether the incremental restore has fallen back to full restore
FallbackFull bool `json:"fallbackFull,omitempty"`
// Activities contains one or more messages about what have been done for this DataDownload.
// +optional
// +nullable
Activities []string `json:"activities,omitempty"`
}
// TODO(2.0) After converting all resources to use the runtime-controller client, the genclient and k8s:deepcopy markers will no longer be needed and should be removed.
@@ -147,7 +147,7 @@ type DataUploadStatus struct {
// +nullable
DataMoverResult *map[string]string `json:"dataMoverResult,omitempty"`
// Message is a message about the DataUpload's status.
// Message is a message describing the DataUpload when it reaches to a terminal status.
// +optional
Message string `json:"message,omitempty"`
@@ -205,6 +205,11 @@ type DataUploadStatus struct {
// FallbackFull indicates whether the incremental backup has fallen back to full backup
FallbackFull bool `json:"fallbackFull,omitempty"`
// Activities contains one or more messages about what have been done for this DataUpload.
// +optional
// +nullable
Activities []string `json:"activities,omitempty"`
}
// TODO(2.0) After converting all resources to use the runttime-controller client,
+2 -3
View File
@@ -621,9 +621,8 @@ func (r *DataDownloadReconciler) OnDataDownloadProgress(ctx context.Context, nam
}
if progress.Message != "" {
message := progress.Message + ";"
if !strings.HasSuffix(dd.Status.Message, message) {
dd.Status.Message += message
if len(dd.Status.Activities) == 0 || dd.Status.Activities[len(dd.Status.Activities)-1] != progress.Message {
dd.Status.Activities = append(dd.Status.Activities, progress.Message)
}
}
@@ -829,7 +829,7 @@ func TestOnDataDownloadProgress(t *testing.T) {
// Call the OnDataDownloadProgress function
r.OnDataDownloadProgress(ctx, namespace, duName, progress)
if len(test.needErrs) != 0 && !test.needErrs[0] {
if len(test.needErrs) == 0 {
// Get the updated DataDownload object from the fake client
updatedDd := &velerov2alpha1api.DataDownload{}
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: duName, Namespace: namespace}, updatedDd))
@@ -845,7 +845,12 @@ func TestOnDataDownloadProgress(t *testing.T) {
assert.Equal(t, int64(0), updatedDd.Status.Progress.BytesDone) // assuming default or original value
}
if progress.Message != "" {
assert.Contains(t, updatedDd.Status.Message, progress.Message)
assert.Contains(t, updatedDd.Status.Activities, progress.Message)
// Call with the same message again to verify deduplication
r.OnDataDownloadProgress(ctx, namespace, duName, progress)
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: duName, Namespace: namespace}, updatedDd))
assert.Equal(t, []string{progress.Message}, updatedDd.Status.Activities)
}
}
})
+2 -3
View File
@@ -648,9 +648,8 @@ func (r *DataUploadReconciler) OnDataUploadProgress(ctx context.Context, namespa
}
if progress.Message != "" {
message := progress.Message + ";"
if !strings.HasSuffix(du.Status.Message, message) {
du.Status.Message += message
if len(du.Status.Activities) == 0 || du.Status.Activities[len(du.Status.Activities)-1] != progress.Message {
du.Status.Activities = append(du.Status.Activities, progress.Message)
}
}
@@ -851,7 +851,7 @@ func TestOnDataUploadProgress(t *testing.T) {
// Call the OnDataUploadProgress function
r.OnDataUploadProgress(ctx, namespace, duName, progress)
if len(test.needErrs) != 0 && !test.needErrs[0] {
if len(test.needErrs) == 0 {
// Get the updated DataUpload object from the fake client
updatedDu := &velerov2alpha1api.DataUpload{}
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: duName, Namespace: namespace}, updatedDu))
@@ -867,7 +867,12 @@ func TestOnDataUploadProgress(t *testing.T) {
assert.Equal(t, int64(0), updatedDu.Status.Progress.BytesDone) // assuming default or original value
}
if progress.Message != "" {
assert.Contains(t, updatedDu.Status.Message, progress.Message)
assert.Contains(t, updatedDu.Status.Activities, progress.Message)
// Call with the same message again to verify deduplication
r.OnDataUploadProgress(ctx, namespace, duName, progress)
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: duName, Namespace: namespace}, updatedDu))
assert.Equal(t, []string{progress.Message}, updatedDu.Status.Activities)
}
}
})
@@ -641,9 +641,8 @@ func (r *PodVolumeBackupReconciler) OnDataPathProgress(ctx context.Context, name
}
if progress.Message != "" {
message := progress.Message + ";"
if !strings.HasSuffix(pvb.Status.Message, message) {
pvb.Status.Message += message
if len(pvb.Status.Activities) == 0 || pvb.Status.Activities[len(pvb.Status.Activities)-1] != progress.Message {
pvb.Status.Activities = append(pvb.Status.Activities, progress.Message)
}
}
@@ -666,7 +666,7 @@ func TestOnPVBProgress(t *testing.T) {
progress := &test.progress
r.OnDataPathProgress(ctx, namespace, pvbName, progress)
if len(test.needErrs) != 0 && !test.needErrs[0] {
if len(test.needErrs) == 0 {
updatedPvb := &velerov1api.PodVolumeBackup{}
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: pvbName, Namespace: namespace}, updatedPvb))
if progress.TotalBytes != -1 {
@@ -680,7 +680,12 @@ func TestOnPVBProgress(t *testing.T) {
assert.Equal(t, int64(0), updatedPvb.Status.Progress.BytesDone) // assuming default or original value
}
if progress.Message != "" {
assert.Contains(t, updatedPvb.Status.Message, progress.Message)
assert.Contains(t, updatedPvb.Status.Activities, progress.Message)
// Call with the same message again to verify deduplication
r.OnDataPathProgress(ctx, namespace, pvbName, progress)
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: pvbName, Namespace: namespace}, updatedPvb))
assert.Equal(t, []string{progress.Message}, updatedPvb.Status.Activities)
}
}
})
@@ -917,9 +917,8 @@ func (r *PodVolumeRestoreReconciler) OnDataPathProgress(ctx context.Context, nam
}
if progress.Message != "" {
message := progress.Message + ";"
if !strings.HasSuffix(pvr.Status.Message, message) {
pvr.Status.Message += message
if len(pvr.Status.Activities) == 0 || pvr.Status.Activities[len(pvr.Status.Activities)-1] != progress.Message {
pvr.Status.Activities = append(pvr.Status.Activities, progress.Message)
}
}
@@ -1512,7 +1512,7 @@ func TestOnPodVolumeRestoreProgress(t *testing.T) {
progress := &test.progress
r.OnDataPathProgress(ctx, namespace, pvrName, progress)
if len(test.needErrs) != 0 && !test.needErrs[0] {
if len(test.needErrs) == 0 {
updatedPVR := &velerov1api.PodVolumeRestore{}
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: pvrName, Namespace: namespace}, updatedPVR))
if progress.TotalBytes != -1 {
@@ -1526,7 +1526,12 @@ func TestOnPodVolumeRestoreProgress(t *testing.T) {
assert.Equal(t, int64(0), updatedPVR.Status.Progress.BytesDone) // assuming default or original value
}
if progress.Message != "" {
assert.Contains(t, updatedPVR.Status.Message, progress.Message)
assert.Contains(t, updatedPVR.Status.Activities, progress.Message)
// Call with the same message again to verify deduplication
r.OnDataPathProgress(ctx, namespace, pvrName, progress)
require.NoError(t, r.client.Get(ctx, types.NamespacedName{Name: pvrName, Namespace: namespace}, updatedPVR))
assert.Equal(t, []string{progress.Message}, updatedPVR.Status.Activities)
}
}
})
@@ -281,7 +281,7 @@ For incremental backups using `velero-block`, Velero will automatically fall bac
- The critical information is missing or cannot be retrieved from the parent snapshot.
- The parent snapshot is missing in the backup repository.
When fallback occurs, unallocated regions are still skipped and identical data blocks remain deduplicated by the backup repository. The backup description will clearly indicate that a fallback took place: `Backup Type: Incremental (fallen back to Full)`.
When fallback occurs, unallocated regions are still skipped and identical data blocks remain deduplicated by the backup repository. The backup description will clearly indicate that a fallback took place: `Backup Type: Incremental (fallen back to Full)`. In addition, the reason for the fallback is captured in the `status.activities` field of the corresponding `DataUpload` CR.
### Monitoring Backup Progress
@@ -331,6 +331,10 @@ You can also view the full `DataUpload` custom resource:
kubectl -n velero get datauploads -l velero.io/backup-name=YOUR_BACKUP_NAME -o yaml
```
In the `DataUpload` status:
- `status.activities`: Lists operational activity and progress messages encountered during data movement, such as incremental fallback reasons.
- `status.message`: Describes the terminal status if the operation failed or was cancelled.
## To restore
You do not need to specify data mover information when creating a restore. Velero automatically retrieves the configurations (data mover type, backup mode, uploader) from the backup metadata.
@@ -371,6 +375,8 @@ You can also view the `DataDownload` custom resources directly:
kubectl -n velero get datadownloads -l velero.io/restore-name=YOUR_RESTORE_NAME -o yaml
```
Similar to `DataUpload`, `status.activities` captures operational activities during data download, while `status.message` describes terminal failure or cancellation details.
## Limitations
- **[Velero Block Data Mover] Linux Node Execution**: Block data mover pods mount raw block devices. Because Windows containers do not support raw block mode volumes, block data mover pods can only run on Linux nodes. However, Windows workloads backed by block storage can still be backed up and restored using the block data mover as long as the data mover pods run on Linux nodes.
@@ -407,6 +413,10 @@ velero restore logs RESTORE_NAME
When reviewing backup details, check whether an incremental backup fell back to full:
- Look for `Backup Type: Incremental (fallen back to Full)` under `Data Movement`. This indicates that CBT metadata retrieval was unsuccessful or the parent snapshot was missing.
- Inspect the specific reason for fallback from `status.activities` on the `DataUpload` CR:
```bash
kubectl -n velero get datauploads -l velero.io/backup-name=BACKUP_NAME -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{range .status.activities}{" - "}{.}{"\n"}{end}{end}'
```
What is the status of your `DataUpload` and `DataDownload`?
@@ -416,6 +426,11 @@ kubectl -n velero get datauploads -l velero.io/backup-name=BACKUP_NAME -o yaml
kubectl -n velero get datadownloads -l velero.io/restore-name=RESTORE_NAME -o yaml
```
Key fields to check in the CR status:
- `status.phase`: Displays the current lifecycle phase (e.g., `Accepted`, `Prepared`, `InProgress`, `Completed`, `Failed`, `Cancelled`).
- `status.activities`: Lists events and progress messages that occurred during data movement (such as fallback details or warnings).
- `status.message`: Details the reason when the CR reaches a terminal failure or cancelled status.
Is there any useful information in the Velero server or data mover pod logs?
```bash