Skip to content

Commit

Permalink
Add warning/error result to cmd velero backup describe
Browse files Browse the repository at this point in the history
Signed-off-by: allenxu404 <[email protected]>
  • Loading branch information
allenxu404 committed Mar 8, 2023
1 parent 38a7707 commit 1134062
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 16 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/5916-allenxu404
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add warning/error result to cmd `velero backup describe`
1 change: 1 addition & 0 deletions config/crd/v1/bases/velero.io_downloadrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ spec:
- BackupVolumeSnapshots
- BackupItemOperations
- BackupResourceList
- BackupResults
- RestoreLog
- RestoreResults
- RestoreResourceList
Expand Down
2 changes: 1 addition & 1 deletion config/crd/v1/crds/crds.go

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion pkg/apis/velero/v1/download_request_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type DownloadRequestSpec struct {
}

// DownloadTargetKind represents what type of file to download.
// +kubebuilder:validation:Enum=BackupLog;BackupContents;BackupVolumeSnapshots;BackupItemOperations;BackupResourceList;RestoreLog;RestoreResults;RestoreResourceList;RestoreItemOperations;CSIBackupVolumeSnapshots;CSIBackupVolumeSnapshotContents
// +kubebuilder:validation:Enum=BackupLog;BackupContents;BackupVolumeSnapshots;BackupItemOperations;BackupResourceList;BackupResults;RestoreLog;RestoreResults;RestoreResourceList;RestoreItemOperations;CSIBackupVolumeSnapshots;CSIBackupVolumeSnapshotContents
type DownloadTargetKind string

const (
Expand All @@ -34,6 +34,7 @@ const (
DownloadTargetKindBackupVolumeSnapshots DownloadTargetKind = "BackupVolumeSnapshots"
DownloadTargetKindBackupItemOperations DownloadTargetKind = "BackupItemOperations"
DownloadTargetKindBackupResourceList DownloadTargetKind = "BackupResourceList"
DownloadTargetKindBackupResults DownloadTargetKind = "BackupResults"
DownloadTargetKindRestoreLog DownloadTargetKind = "RestoreLog"
DownloadTargetKindRestoreResults DownloadTargetKind = "RestoreResults"
DownloadTargetKindRestoreResourceList DownloadTargetKind = "RestoreResourceList"
Expand Down
40 changes: 38 additions & 2 deletions pkg/cmd/util/output/backup_describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/features"
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
"github.com/vmware-tanzu/velero/pkg/itemoperation"
"github.com/vmware-tanzu/velero/pkg/util/results"
"github.com/vmware-tanzu/velero/pkg/volume"
)

Expand Down Expand Up @@ -90,8 +91,7 @@ func DescribeBackup(
}

d.Println()
d.Printf("Errors:\t%d\n", status.Errors)
d.Printf("Warnings:\t%d\n", status.Warnings)
DescribeBackupResults(ctx, kbClient, d, backup, insecureSkipTLSVerify, caCertFile)

d.Println()
DescribeBackupSpec(d, backup.Spec)
Expand Down Expand Up @@ -632,3 +632,39 @@ func DescribeVSC(d *Describer, details bool, vsc snapshotv1api.VolumeSnapshotCon
d.Printf("\tReady to use: %t\n", *vsc.Status.ReadyToUse)
}
}

// DescribeBackupResults describes errors and warnings in human-readable format.
func DescribeBackupResults(ctx context.Context, kbClient kbclient.Client, d *Describer, backup *velerov1api.Backup, insecureSkipTLSVerify bool, caCertPath string) {
if backup.Status.Warnings == 0 && backup.Status.Errors == 0 {
return
}

var buf bytes.Buffer
var resultMap map[string]results.Result

// If err 'ErrNotFound' occurs, it means the backup bundle in the bucket has already been there before the backup-result file is introduced.
// We only display the count of errors and warnings in this case.
err := downloadrequest.Stream(ctx, kbClient, backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupResults, &buf, downloadRequestTimeout, insecureSkipTLSVerify, caCertPath)
if err == downloadrequest.ErrNotFound {
d.Printf("Errors:\t%d\n", backup.Status.Errors)
d.Printf("Warnings:\t%d\n", backup.Status.Warnings)
return
} else if err != nil {
d.Printf("Warnings:\t<error getting warnings: %v>\n\nErrors:\t<error getting errors: %v>\n", err, err)
return
}

if err := json.NewDecoder(&buf).Decode(&resultMap); err != nil {
d.Printf("Warnings:\t<error decoding warnings: %v>\n\nErrors:\t<error decoding errors: %v>\n", err, err)
return
}

if backup.Status.Warnings > 0 {
d.Println()
describeResult(d, "Warnings", resultMap["warnings"])
}
if backup.Status.Errors > 0 {
d.Println()
describeResult(d, "Errors", resultMap["errors"])
}
}
74 changes: 65 additions & 9 deletions pkg/cmd/util/output/backup_structured_describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
"github.com/vmware-tanzu/velero/pkg/features"
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
"github.com/vmware-tanzu/velero/pkg/util/results"
"github.com/vmware-tanzu/velero/pkg/volume"
)

Expand Down Expand Up @@ -60,8 +61,7 @@ func DescribeBackupInSF(
d.Describe("validationErrors", status.ValidationErrors)
}

d.Describe("errors", status.Errors)
d.Describe("warnings", status.Warnings)
DescribeBackupResultsInSF(ctx, kbClient, d, backup, insecureSkipTLSVerify, caCertFile)

DescribeBackupSpecInSF(d, backup.Spec)

Expand Down Expand Up @@ -266,7 +266,7 @@ func DescribeBackupStatusInSF(ctx context.Context, kbClient kbclient.Client, d *

// In consideration of decoding structured output conveniently, the three separate fields were created here
// the field of "veleroNativeSnapshots" displays the brief snapshots info
// the field of "veleroNativeSnapshotsError" displays the error message if it fails to get snapshot info
// the field of "errorGettingSnapshots" displays the error message if it fails to get snapshot info
// the field of "veleroNativeSnapshotsDetail" displays the detailed snapshots info
if status.VolumeSnapshotsAttempted > 0 {
if !details {
Expand All @@ -276,13 +276,13 @@ func DescribeBackupStatusInSF(ctx context.Context, kbClient kbclient.Client, d *

buf := new(bytes.Buffer)
if err := downloadrequest.Stream(ctx, kbClient, backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupVolumeSnapshots, buf, downloadRequestTimeout, insecureSkipTLSVerify, caCertPath); err != nil {
backupStatusInfo["veleroNativeSnapshotsError"] = fmt.Sprintf("<error getting snapshot info: %v>", err)
backupStatusInfo["errorGettingSnapshots"] = fmt.Sprintf("<error getting snapshot info: %v>", err)
return
}

var snapshots []*volume.Snapshot
if err := json.NewDecoder(buf).Decode(&snapshots); err != nil {
backupStatusInfo["veleroNativeSnapshotsError"] = fmt.Sprintf("<error reading snapshot info: %v>", err)
backupStatusInfo["errorGettingSnapshots"] = fmt.Sprintf("<error reading snapshot info: %v>", err)
return
}

Expand All @@ -298,7 +298,7 @@ func DescribeBackupStatusInSF(ctx context.Context, kbClient kbclient.Client, d *

func describeBackupResourceListInSF(ctx context.Context, kbClient kbclient.Client, backupStatusInfo map[string]interface{}, backup *velerov1api.Backup, insecureSkipTLSVerify bool, caCertPath string) {
// In consideration of decoding structured output conveniently, the two separate fields were created here(in func describeBackupResourceList, there is only one field describing either error message or resource list)
// the field of 'resourceListError' gives specific error message when it fails to get resources list
// the field of 'errorGettingResourceList' gives specific error message when it fails to get resources list
// the field of 'resourceList' lists the rearranged resources
buf := new(bytes.Buffer)
if err := downloadrequest.Stream(ctx, kbClient, backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupResourceList, buf, downloadRequestTimeout, insecureSkipTLSVerify, caCertPath); err != nil {
Expand All @@ -308,16 +308,16 @@ func describeBackupResourceListInSF(ctx context.Context, kbClient kbclient.Clien
// - the backup hasn't completed yet; or
// - there was an error uploading the file; or
// - the file was manually deleted after upload
backupStatusInfo["resourceListError"] = "<backup resource list not found>"
backupStatusInfo["errorGettingResourceList"] = "<backup resource list not found>"
} else {
backupStatusInfo["resourceListError"] = fmt.Sprintf("<error getting backup resource list: %v>", err)
backupStatusInfo["errorGettingResourceList"] = fmt.Sprintf("<error getting backup resource list: %v>", err)
}
return
}

var resourceList map[string][]string
if err := json.NewDecoder(buf).Decode(&resourceList); err != nil {
backupStatusInfo["resourceListError"] = fmt.Sprintf("<error reading backup resource list: %v>\n", err)
backupStatusInfo["errorGettingResourceList"] = fmt.Sprintf("<error reading backup resource list: %v>\n", err)
return
}
backupStatusInfo["resourceList"] = resourceList
Expand Down Expand Up @@ -460,3 +460,59 @@ func DescribeVSCInSF(details bool, vsc snapshotv1api.VolumeSnapshotContent, vscD
}
vscDetails[vsc.Name] = content
}

// DescribeBackupResultsInSF describes errors and warnings in structured format.
func DescribeBackupResultsInSF(ctx context.Context, kbClient kbclient.Client, d *StructuredDescriber, backup *velerov1api.Backup, insecureSkipTLSVerify bool, caCertPath string) {
if backup.Status.Warnings == 0 && backup.Status.Errors == 0 {
return
}

var buf bytes.Buffer
var resultMap map[string]results.Result

errors, warnings := make(map[string]interface{}), make(map[string]interface{})
defer func() {
d.Describe("errors", errors)
d.Describe("warnings", warnings)
}()

// If 'ErrNotFound' occurs, it means the backup bundle in the bucket has already been there before the backup-result file is introduced.
// We only display the count of errors and warnings in this case.
err := downloadrequest.Stream(ctx, kbClient, backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupResults, &buf, downloadRequestTimeout, insecureSkipTLSVerify, caCertPath)
if err == downloadrequest.ErrNotFound {
errors["count"] = backup.Status.Errors
warnings["count"] = backup.Status.Warnings
return
} else if err != nil {
errors["errorGettingErrors"] = fmt.Errorf("<error getting errors: %v>", err)
warnings["errorGettingWarnings"] = fmt.Errorf("<error getting warnings: %v>", err)
return
}

if err := json.NewDecoder(&buf).Decode(&resultMap); err != nil {
errors["errorGettingErrors"] = fmt.Errorf("<error decoding errors: %v>", err)
warnings["errorGettingWarnings"] = fmt.Errorf("<error decoding warnings: %v>", err)
return
}

if backup.Status.Warnings > 0 {
describeResultInSF(warnings, resultMap["warnings"])
}
if backup.Status.Errors > 0 {
describeResultInSF(errors, resultMap["errors"])
}
}

func describeResultInSF(m map[string]interface{}, result results.Result) {
m["velero"], m["cluster"], m["namespace"] = []string{}, []string{}, []string{}

if len(result.Velero) > 0 {
m["velero"] = result.Velero
}
if len(result.Cluster) > 0 {
m["cluster"] = result.Cluster
}
if len(result.Namespaces) > 0 {
m["namespace"] = result.Namespaces
}
}
6 changes: 3 additions & 3 deletions pkg/cmd/util/output/restore_describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,15 @@ func describeRestoreResults(ctx context.Context, kbClient kbclient.Client, d *De

if restore.Status.Warnings > 0 {
d.Println()
describeRestoreResult(d, "Warnings", resultMap["warnings"])
describeResult(d, "Warnings", resultMap["warnings"])
}
if restore.Status.Errors > 0 {
d.Println()
describeRestoreResult(d, "Errors", resultMap["errors"])
describeResult(d, "Errors", resultMap["errors"])
}
}

func describeRestoreResult(d *Describer, name string, result results.Result) {
func describeResult(d *Describer, name string, result results.Result) {
d.Printf("%s:\n", name)
d.DescribeSlice(1, "Velero", result.Velero)
d.DescribeSlice(1, "Cluster", result.Cluster)
Expand Down
2 changes: 2 additions & 0 deletions pkg/persistence/object_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,8 @@ func (s *objectBackupStore) GetDownloadURL(target velerov1api.DownloadTarget) (s
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getCSIVolumeSnapshotKey(target.Name), DownloadURLTTL)
case velerov1api.DownloadTargetKindCSIBackupVolumeSnapshotContents:
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getCSIVolumeSnapshotContentsKey(target.Name), DownloadURLTTL)
case velerov1api.DownloadTargetKindBackupResults:
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getBackupResultsKey(target.Name), DownloadURLTTL)
default:
return "", errors.Errorf("unsupported download target kind %q", target.Kind)
}
Expand Down

0 comments on commit 1134062

Please sign in to comment.