issue 6695: add backup describe for CSI snapshot data movement 02
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>pull/7125/head
parent
582be97a63
commit
4e4f0aa1da
|
@ -0,0 +1 @@
|
|||
Fix issue #6695, add describe for data mover backups
|
|
@ -53,6 +53,7 @@ spec:
|
|||
- RestoreItemOperations
|
||||
- CSIBackupVolumeSnapshots
|
||||
- CSIBackupVolumeSnapshotContents
|
||||
- BackupVolumeInfos
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of the Kubernetes resource with
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -21,8 +21,6 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
snapshotv1client "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
@ -32,7 +30,6 @@ import (
|
|||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
|
||||
"github.com/vmware-tanzu/velero/pkg/features"
|
||||
"github.com/vmware-tanzu/velero/pkg/label"
|
||||
)
|
||||
|
||||
|
@ -57,14 +54,6 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
|||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
|
||||
var csiClient *snapshotv1client.Clientset
|
||||
if features.IsEnabled(velerov1api.CSIFeatureFlag) {
|
||||
clientConfig, err := f.ClientConfig()
|
||||
cmd.CheckError(err)
|
||||
csiClient, err = snapshotv1client.NewForConfig(clientConfig)
|
||||
cmd.CheckError(err)
|
||||
}
|
||||
|
||||
if outputFormat != "plaintext" && outputFormat != "json" {
|
||||
cmd.CheckError(fmt.Errorf("invalid output format '%s'. valid value are 'plaintext, json'", outputFormat))
|
||||
}
|
||||
|
@ -104,23 +93,13 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
|||
fmt.Fprintf(os.Stderr, "error getting PodVolumeBackups for backup %s: %v\n", backup.Name, err)
|
||||
}
|
||||
|
||||
// declare vscList up here since it may be empty and we'll pass the empty Items field into DescribeBackup
|
||||
vscList := new(snapshotv1api.VolumeSnapshotContentList)
|
||||
if features.IsEnabled(velerov1api.CSIFeatureFlag) {
|
||||
opts := label.NewListOptionsForBackup(backup.Name)
|
||||
vscList, err = csiClient.SnapshotV1().VolumeSnapshotContents().List(context.TODO(), opts)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting VolumeSnapshotContent objects for backup %s: %v\n", backup.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// structured output only applies to a single backup in case of OOM
|
||||
// To describe the list of backups in structured format, users could iterate over the list and describe backup one after another.
|
||||
if len(backups.Items) == 1 && outputFormat != "plaintext" {
|
||||
s := output.DescribeBackupInSF(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, insecureSkipTLSVerify, caCertFile, outputFormat)
|
||||
s := output.DescribeBackupInSF(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, details, insecureSkipTLSVerify, caCertFile, outputFormat)
|
||||
fmt.Print(s)
|
||||
} else {
|
||||
s := output.DescribeBackup(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, insecureSkipTLSVerify, caCertFile)
|
||||
s := output.DescribeBackup(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, details, insecureSkipTLSVerify, caCertFile)
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
|
|
|
@ -39,7 +39,7 @@ func TestNewDescribeCommand(t *testing.T) {
|
|||
// create a factory
|
||||
f := &factorymocks.Factory{}
|
||||
backupName := "bk-describe-1"
|
||||
testBackup := builder.ForBackup(cmdtest.VeleroNameSpace, backupName).Result()
|
||||
testBackup := builder.ForBackup(cmdtest.VeleroNameSpace, backupName).SnapshotVolumes(false).Result()
|
||||
|
||||
clientConfig := rest.Config{}
|
||||
kbClient := test.NewFakeControllerRuntimeClient(t)
|
||||
|
@ -68,7 +68,7 @@ func TestNewDescribeCommand(t *testing.T) {
|
|||
stdout, _, err := veleroexec.RunCommand(cmd)
|
||||
|
||||
if err == nil {
|
||||
assert.Contains(t, stdout, "Velero-Native Snapshots: <none included>")
|
||||
assert.Contains(t, stdout, "Backup Volumes: <none included>")
|
||||
assert.Contains(t, stdout, "Or label selector: <none>")
|
||||
assert.Contains(t, stdout, fmt.Sprintf("Name: %s", backupName))
|
||||
return
|
||||
|
|
|
@ -27,8 +27,6 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
|
||||
"github.com/fatih/color"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
|
@ -38,6 +36,7 @@ import (
|
|||
"github.com/vmware-tanzu/velero/pkg/features"
|
||||
"github.com/vmware-tanzu/velero/pkg/itemoperation"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/collections"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/results"
|
||||
"github.com/vmware-tanzu/velero/pkg/volume"
|
||||
|
@ -50,7 +49,6 @@ func DescribeBackup(
|
|||
backup *velerov1api.Backup,
|
||||
deleteRequests []velerov1api.DeleteBackupRequest,
|
||||
podVolumeBackups []velerov1api.PodVolumeBackup,
|
||||
volumeSnapshotContents []snapshotv1api.VolumeSnapshotContent,
|
||||
details bool,
|
||||
insecureSkipTLSVerify bool,
|
||||
caCertFile string,
|
||||
|
@ -347,6 +345,7 @@ func DescribeBackupStatus(ctx context.Context, kbClient kbclient.Client, d *Desc
|
|||
}
|
||||
|
||||
describeBackupVolumes(ctx, kbClient, d, backup, details, insecureSkipTLSVerify, caCertPath, podVolumeBackups)
|
||||
|
||||
d.Println()
|
||||
}
|
||||
|
||||
|
@ -415,6 +414,11 @@ func describeBackupResourceList(ctx context.Context, kbClient kbclient.Client, d
|
|||
|
||||
func describeBackupVolumes(ctx context.Context, kbClient kbclient.Client, d *Describer, backup *velerov1api.Backup, details bool,
|
||||
insecureSkipTLSVerify bool, caCertPath string, podVolumeBackupCRs []velerov1api.PodVolumeBackup) {
|
||||
if boolptr.IsSetToFalse(backup.Spec.SnapshotVolumes) {
|
||||
d.Println("Backup Volumes: <none included>")
|
||||
return
|
||||
}
|
||||
|
||||
d.Println("Backup Volumes:")
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
@ -431,12 +435,12 @@ func describeBackupVolumes(ctx context.Context, kbClient kbclient.Client, d *Des
|
|||
|
||||
nativeSnapshots := []*volume.VolumeInfo{}
|
||||
csiSnapshots := []*volume.VolumeInfo{}
|
||||
for _, info := range volumeInfos.VolumeInfos {
|
||||
switch info.BackupMethod {
|
||||
for i := range volumeInfos.VolumeInfos {
|
||||
switch volumeInfos.VolumeInfos[i].BackupMethod {
|
||||
case volume.NativeSnapshot:
|
||||
nativeSnapshots = append(nativeSnapshots, &info)
|
||||
nativeSnapshots = append(nativeSnapshots, &volumeInfos.VolumeInfos[i])
|
||||
case volume.CSISnapshot:
|
||||
csiSnapshots = append(csiSnapshots, &info)
|
||||
csiSnapshots = append(csiSnapshots, &volumeInfos.VolumeInfos[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,13 +26,12 @@ import (
|
|||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/downloadrequest"
|
||||
"github.com/vmware-tanzu/velero/pkg/features"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/results"
|
||||
"github.com/vmware-tanzu/velero/pkg/volume"
|
||||
)
|
||||
|
@ -44,7 +43,6 @@ func DescribeBackupInSF(
|
|||
backup *velerov1api.Backup,
|
||||
deleteRequests []velerov1api.DeleteBackupRequest,
|
||||
podVolumeBackups []velerov1api.PodVolumeBackup,
|
||||
volumeSnapshotContents []snapshotv1api.VolumeSnapshotContent,
|
||||
details bool,
|
||||
insecureSkipTLSVerify bool,
|
||||
caCertFile string,
|
||||
|
@ -267,9 +265,7 @@ func DescribeBackupStatusInSF(ctx context.Context, kbClient kbclient.Client, d *
|
|||
describeBackupResourceListInSF(ctx, kbClient, backupStatusInfo, backup, insecureSkipTLSVerify, caCertPath)
|
||||
}
|
||||
|
||||
backupVolumes := make(map[string]interface{})
|
||||
describeBackupVolumesInSF(ctx, kbClient, backup, details, insecureSkipTLSVerify, caCertPath, podVolumeBackups, backupVolumes)
|
||||
backupStatusInfo["backupVolumes"] = backupVolumes
|
||||
describeBackupVolumesInSF(ctx, kbClient, backup, details, insecureSkipTLSVerify, caCertPath, podVolumeBackups, backupStatusInfo)
|
||||
}
|
||||
|
||||
func describeBackupResourceListInSF(ctx context.Context, kbClient kbclient.Client, backupStatusInfo map[string]interface{}, backup *velerov1api.Backup, insecureSkipTLSVerify bool, caCertPath string) {
|
||||
|
@ -300,7 +296,13 @@ func describeBackupResourceListInSF(ctx context.Context, kbClient kbclient.Clien
|
|||
}
|
||||
|
||||
func describeBackupVolumesInSF(ctx context.Context, kbClient kbclient.Client, backup *velerov1api.Backup, details bool,
|
||||
insecureSkipTLSVerify bool, caCertPath string, podVolumeBackupCRs []velerov1api.PodVolumeBackup, backupVolumes map[string]interface{}) {
|
||||
insecureSkipTLSVerify bool, caCertPath string, podVolumeBackupCRs []velerov1api.PodVolumeBackup, backupStatusInfo map[string]interface{}) {
|
||||
if boolptr.IsSetToFalse(backup.Spec.SnapshotVolumes) {
|
||||
backupStatusInfo["backupVolumes"] = "<none included>"
|
||||
return
|
||||
}
|
||||
|
||||
backupVolumes := make(map[string]interface{})
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := downloadrequest.Stream(ctx, kbClient, backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupVolumeInfos, buf, downloadRequestTimeout, insecureSkipTLSVerify, caCertPath); err != nil {
|
||||
|
@ -316,12 +318,12 @@ func describeBackupVolumesInSF(ctx context.Context, kbClient kbclient.Client, ba
|
|||
|
||||
nativeSnapshots := []*volume.VolumeInfo{}
|
||||
csiSnapshots := []*volume.VolumeInfo{}
|
||||
for _, info := range volumeInfos.VolumeInfos {
|
||||
switch info.BackupMethod {
|
||||
for i := range volumeInfos.VolumeInfos {
|
||||
switch volumeInfos.VolumeInfos[i].BackupMethod {
|
||||
case volume.NativeSnapshot:
|
||||
nativeSnapshots = append(nativeSnapshots, &info)
|
||||
nativeSnapshots = append(nativeSnapshots, &volumeInfos.VolumeInfos[i])
|
||||
case volume.CSISnapshot:
|
||||
csiSnapshots = append(csiSnapshots, &info)
|
||||
csiSnapshots = append(csiSnapshots, &volumeInfos.VolumeInfos[i])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,11 +334,14 @@ func describeBackupVolumesInSF(ctx context.Context, kbClient kbclient.Client, ba
|
|||
backupVolumes["csiSnapshots"] = csiSnapshotDetails
|
||||
|
||||
describePodVolumeBackupsInSF(podVolumeBackupCRs, details, backupVolumes)
|
||||
|
||||
backupStatusInfo["backupVolumes"] = backupVolumes
|
||||
}
|
||||
|
||||
func describeNativeSnapshotsInSF(details bool, infos []*volume.VolumeInfo, backupVolumes map[string]interface{}) {
|
||||
if len(infos) == 0 {
|
||||
backupVolumes["nativeSnapshots"] = "<none included>"
|
||||
return
|
||||
}
|
||||
|
||||
snapshotDetails := make(map[string]interface{})
|
||||
|
@ -347,7 +352,6 @@ func describeNativeSnapshotsInSF(details bool, infos []*volume.VolumeInfo, backu
|
|||
}
|
||||
|
||||
func describNativeSnapshotInSF(details bool, info *volume.VolumeInfo, snapshotDetails map[string]interface{}) {
|
||||
|
||||
if details {
|
||||
snapshotInfo := make(map[string]string)
|
||||
snapshotInfo["snapshotID"] = info.NativeSnapshotInfo.SnapshotHandle
|
||||
|
|
|
@ -266,7 +266,7 @@ func TestDescribePodVolumeBackupsInSF(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDescribeSnapshotInSF(t *testing.T) {
|
||||
func TestDescribeNativeSnapshotsInSF(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
volumeInfo []*volume.VolumeInfo
|
||||
|
|
Loading…
Reference in New Issue