mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-09-27 18:34:18 +00:00
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
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:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user