Include CSI volume snapshot information in `velero backup describe` (#2448)
* Add download methods for CSI objects Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add support for downloading CSI volume objects Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add new methods to mock. Remove generated information from file since mockery no longer appears to work. It isn't maintained anymore and doesn't support go module-based projects. Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add describe command for CSI Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add csi package with helpers Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove duplicate import from server Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove CSI API that will not be used with describe Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add VolumeSnapshotContents output to describe command Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Document NewCSIListOptions function Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Document csi package Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove stutter in function name Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Fix CI Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Fix nil pointer error when not using CSI snapshots Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove unused CSI download request kinds Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add back mocks Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Change persistent volumes to velero-native snapshots Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove unused function Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Address review feedback Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add changelog Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Remove unnecessary doc.go Signed-off-by: Nolan Brubaker <brubakern@vmware.com>pull/2525/head
parent
f1eeff7a91
commit
e400be9c8f
|
@ -0,0 +1 @@
|
|||
Add details of CSI volumesnapshotcontents associated with a backup to `velero backup describe` when the `EnableCSI` feature flag is given on the velero client.
|
|
@ -23,11 +23,15 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
v1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
snapshotv1beta1api "github.com/kubernetes-csi/external-snapshotter/v2/pkg/apis/volumesnapshot/v1beta1"
|
||||
snapshotv1beta1client "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
pkgbackup "github.com/vmware-tanzu/velero/pkg/backup"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -51,9 +55,9 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
|||
veleroClient, err := f.Client()
|
||||
cmd.CheckError(err)
|
||||
|
||||
var backups *v1.BackupList
|
||||
var backups *velerov1api.BackupList
|
||||
if len(args) > 0 {
|
||||
backups = new(v1.BackupList)
|
||||
backups = new(velerov1api.BackupList)
|
||||
for _, name := range args {
|
||||
backup, err := veleroClient.VeleroV1().Backups(f.Namespace()).Get(name, metav1.GetOptions{})
|
||||
cmd.CheckError(err)
|
||||
|
@ -78,7 +82,23 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
|||
fmt.Fprintf(os.Stderr, "error getting PodVolumeBackups for backup %s: %v\n", backup.Name, err)
|
||||
}
|
||||
|
||||
s := output.DescribeBackup(&backup, deleteRequestList.Items, podVolumeBackupList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
var csiClient *snapshotv1beta1client.Clientset
|
||||
// declare vscList up here since it may be empty and we'll pass the empty Items field into DescribeBackup
|
||||
vscList := new(snapshotv1beta1api.VolumeSnapshotContentList)
|
||||
if features.IsEnabled(velerov1api.CSIFeatureFlag) {
|
||||
clientConfig, err := f.ClientConfig()
|
||||
cmd.CheckError(err)
|
||||
|
||||
csiClient, err = snapshotv1beta1client.NewForConfig(clientConfig)
|
||||
cmd.CheckError(err)
|
||||
|
||||
vscList, err = csiClient.SnapshotV1beta1().VolumeSnapshotContents().List(opts)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting VolumeSnapshotContent objects for backup %s: %v\n", backup.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
s := output.DescribeBackup(&backup, deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
|
|
|
@ -28,7 +28,6 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
snapshotterClientSet "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -229,7 +228,7 @@ type server struct {
|
|||
dynamicClient dynamic.Interface
|
||||
sharedInformerFactory informers.SharedInformerFactory
|
||||
csiSnapshotterSharedInformerFactory *CSIInformerFactoryWrapper
|
||||
csiSnapshotClient *snapshotterClientSet.Clientset
|
||||
csiSnapshotClient *snapshotv1beta1client.Clientset
|
||||
ctx context.Context
|
||||
cancelFunc context.CancelFunc
|
||||
logger logrus.FieldLogger
|
||||
|
|
|
@ -25,8 +25,11 @@ import (
|
|||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
snapshotv1beta1api "github.com/kubernetes-csi/external-snapshotter/v2/pkg/apis/volumesnapshot/v1beta1"
|
||||
|
||||
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"
|
||||
clientset "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned"
|
||||
"github.com/vmware-tanzu/velero/pkg/volume"
|
||||
)
|
||||
|
@ -36,6 +39,7 @@ func DescribeBackup(
|
|||
backup *velerov1api.Backup,
|
||||
deleteRequests []velerov1api.DeleteBackupRequest,
|
||||
podVolumeBackups []velerov1api.PodVolumeBackup,
|
||||
volumeSnapshotContents []snapshotv1beta1api.VolumeSnapshotContent,
|
||||
details bool,
|
||||
veleroClient clientset.Interface,
|
||||
insecureSkipTLSVerify bool,
|
||||
|
@ -87,6 +91,10 @@ func DescribeBackup(
|
|||
d.Println()
|
||||
DescribePodVolumeBackups(d, podVolumeBackups, details)
|
||||
}
|
||||
|
||||
if features.IsEnabled(velerov1api.CSIFeatureFlag) {
|
||||
DescribeCSIVolumeSnapshots(d, details, volumeSnapshotContents)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -136,7 +144,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
|||
d.Printf("Storage Location:\t%s\n", spec.StorageLocation)
|
||||
|
||||
d.Println()
|
||||
d.Printf("Snapshot PVs:\t%s\n", BoolPointerString(spec.SnapshotVolumes, "false", "true", "auto"))
|
||||
d.Printf("Velero-Native Snapshot PVs:\t%s\n", BoolPointerString(spec.SnapshotVolumes, "false", "true", "auto"))
|
||||
|
||||
d.Println()
|
||||
d.Printf("TTL:\t%s\n", spec.TTL.Duration)
|
||||
|
@ -257,30 +265,30 @@ func DescribeBackupStatus(d *Describer, backup *velerov1api.Backup, details bool
|
|||
|
||||
if status.VolumeSnapshotsAttempted > 0 {
|
||||
if !details {
|
||||
d.Printf("Persistent Volumes:\t%d of %d snapshots completed successfully (specify --details for more information)\n", status.VolumeSnapshotsCompleted, status.VolumeSnapshotsAttempted)
|
||||
d.Printf("Velero-Native Snapshots:\t%d of %d snapshots completed successfully (specify --details for more information)\n", status.VolumeSnapshotsCompleted, status.VolumeSnapshotsAttempted)
|
||||
return
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if err := downloadrequest.Stream(veleroClient.VeleroV1(), backup.Namespace, backup.Name, velerov1api.DownloadTargetKindBackupVolumeSnapshots, buf, downloadRequestTimeout, insecureSkipTLSVerify, caCertPath); err != nil {
|
||||
d.Printf("Persistent Volumes:\t<error getting volume snapshot info: %v>\n", err)
|
||||
d.Printf("Velero-Native Snapshots:\t<error getting snapshot info: %v>\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
var snapshots []*volume.Snapshot
|
||||
if err := json.NewDecoder(buf).Decode(&snapshots); err != nil {
|
||||
d.Printf("Persistent Volumes:\t<error reading volume snapshot info: %v>\n", err)
|
||||
d.Printf("Velero-Native Snapshots:\t<error reading snapshot info: %v>\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
d.Printf("Persistent Volumes:\n")
|
||||
d.Printf("Velero-Native Snapshots:\n")
|
||||
for _, snap := range snapshots {
|
||||
describeSnapshot(d, snap.Spec.PersistentVolumeName, snap.Status.ProviderSnapshotID, snap.Spec.VolumeType, snap.Spec.VolumeAZ, snap.Spec.VolumeIOPS)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
d.Printf("Persistent Volumes: <none included>\n")
|
||||
d.Printf("Velero-Native Snapshots: <none included>\n")
|
||||
}
|
||||
|
||||
func describeBackupResourceList(d *Describer, backup *velerov1api.Backup, veleroClient clientset.Interface, insecureSkipTLSVerify bool, caCertPath string) {
|
||||
|
@ -479,3 +487,40 @@ func (v *volumesByPod) Sorted() []*podVolumeGroup {
|
|||
|
||||
return v.volumesByPodSlice
|
||||
}
|
||||
|
||||
func DescribeCSIVolumeSnapshots(d *Describer, details bool, volumeSnapshotContents []snapshotv1beta1api.VolumeSnapshotContent) {
|
||||
if !features.IsEnabled(velerov1api.CSIFeatureFlag) {
|
||||
return
|
||||
}
|
||||
|
||||
if !details {
|
||||
d.Printf("CSI Volume Snapshots:\t%d included (specify --details for more information)\n", len(volumeSnapshotContents))
|
||||
return
|
||||
}
|
||||
d.Printf("CSI Volume Snapshots:\n")
|
||||
|
||||
for _, vsc := range volumeSnapshotContents {
|
||||
DescribeVSC(d, details, vsc)
|
||||
}
|
||||
}
|
||||
|
||||
func DescribeVSC(d *Describer, details bool, vsc snapshotv1beta1api.VolumeSnapshotContent) {
|
||||
if vsc.Status == nil {
|
||||
d.Printf("Volume Snapshot Content %s cannot be described because its status is nil\n", vsc.Name)
|
||||
return
|
||||
}
|
||||
|
||||
d.Printf("Snapshot Content Name: %s\n", vsc.Name)
|
||||
|
||||
if vsc.Status.SnapshotHandle != nil {
|
||||
d.Printf("\tStorage Snapshot ID: %s\n", *vsc.Status.SnapshotHandle)
|
||||
}
|
||||
|
||||
if vsc.Status.RestoreSize != nil {
|
||||
d.Printf("\tSnapshot Size (bytes): %d\n", *vsc.Status.RestoreSize)
|
||||
}
|
||||
|
||||
if vsc.Status.ReadyToUse != nil {
|
||||
d.Printf("\tReady to use: %t\n", *vsc.Status.ReadyToUse)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue